React collapsing div animation with CSS - javascript

I don't really understand why my component doesn't work. I want to create a component which expand/collapse when you click the button. It works fine, but I have a problem with the animation. When I click the button, website crashes. This is my component:
import { useState, useRef, React } from 'react'
const Collapsible = ({ desc, text }) => {
const [isOpen, setIsOpen] = useState(false);
const parentRef = useRef();
return (
<div className='city'>
<button className='toggle-btn' onClick={()=> {
setIsOpen(!isOpen);
}}>{text}</button>
{ isOpen &&
<div
className="city-info"
ref={parentRef}
style={isOpen ? {
height: parentRef.current.scrollHeight + "px",
}:{
height: "0px",
}}
>{desc}</div>}
</div>
)
}
export default Collapsible
And this is the error I get:
Uncaught TypeError: Cannot read properties of undefined (reading 'scrollHeight')
Why is it undefined? After a long time of trying to do it by myself, I gave up and I did a step-by-step with tutorial and it works great in the tutorial.

Related

Trying to not fire a transition event when reloading the page

import { IconButton } from "#mui/material";
import React, { useState, useEffect } from "react";
import { Brightness4, Brightness7 } from "#mui/icons-material";
const ThemeChanger = () => {
const [themeState, setThemeState] = useState(false);
useEffect(() => {
const getTheme = localStorage.getItem("Theme");
if (getTheme === "dark") {
setThemeState(true);
} else {
}
}, []);
useEffect(() => {
if (themeState) {
localStorage.setItem("Theme", "dark");
document.body.classList.add("dark-mode");
} else {
localStorage.setItem("Theme", "light");
document.body.classList.remove("dark-mode");
}
}, [themeState]);
return (
<div>
<IconButton
className="icon-button"
style={{ marginTop: "16px" }}
onClick={() => {
setThemeState(!themeState);
document.body.classList.add("dark-light-toggle-transition");
}}
>
{themeState ? <Brightness4 /> : <Brightness7 />}
</IconButton>
</div>
);
};
export default ThemeChanger;
I am trying to make the former component to not fire the event of the transition that I have in "dark-mode" when I reload the page. The component is capable of toggling a dark mode.
I tried a bit of jQuery and the window.performance event but I could not make it work. I think the solution is not that hard but I am really loaded and my brain is not functioning anymore. Is there anyone who could help me?
P.S. I used a "preload" class with jQuery and set the class of the body into transition: none, however the problem is the useEffect as when the state is true it always adds the "dark-mode" class.
Thanks in advance!
EDIT: Actually I made it work. I just made a class called "dark-light-toggle-transition" which essentially is doing the work for me. I put it inside the jsx ThemeChanger component so it is only applied when I press the toggle button! If anyone needs more information, you can send me here!

document.getElementById('pwMeter').style.display='none' not working as expected

I'm trying to hide a div using the following method in a react web page. But it doesn't hide the element. I can't see any errors in the developer tools as well.
if(pw.length==0){
document.getElementById('pwMeter').style.display='none'
}
What is the problem here? Does React support this method?
yes with react you can do this , check this sample ref code for that
import { useState } from "react";
const TestFunction = (props) => {
const [pw, setpw] = useState(["test"]);
return (
<div>
<div
id="pwMeter"
style={pw && pw.length > 0 ? { display: "bock" } : { display: "none" }}
>
<p>test data</p>
</div>
</div>
);
};
export default TestFunction;

trouble using set state correctly to update an event in react Big Calender

I am trying to implement react big calendar however I am having an issue with adding an event and using set state to update the event.I created a my calendar component then use the handle select function to take the new event and set the state but im not sure how I can set the state correctly. The documentation for set state uses render but I don't use render to display the calendar. Im not sure where I would need the constructor method or what I might be missing.
the current error is
TypeError: Cannot read property 'setState' of undefined
import React, { useState } from "react";
import "react-big-calendar/lib/css/react-big-calendar.css";
import Navigation from "../components/Navigation";
import events from "./events";
import { Calendar, momentLocalizer } from "react-big-calendar";
import moment from "moment";
const localizer = momentLocalizer(moment);
const handleSelect = ({ start, end }) => {
const title = window.prompt("New Event name");
alert("title " + title);
if (title) {
this.setState({
events: [
this.state.events,
{
start,
end,
title,
},
],
});
console.log(events);
}
};
const MyCalendar = (props) => (
<div>
<Navigation />
<Calendar
selectable
localizer={localizer}
events={events}
popup
startAccessor="start"
endAccessor="end"
style={{ height: 700 }}
onSelectSlot={handleSelect}
/>
</div>
);
export default MyCalendar;
The keyword this does nothing in the world of functional programming. It is a concept of OOP. Don't mix them up.
Instead, do the following
import { useState } from "react";
import moment from "moment"; // bad practice BTW, moment is huge. You should only import the part you need instead of the entire package
const MyCalendar = props => {
const [events, setEvents] = useState([]);
const handleSelect = ({ start, end }) => {
const title = window.prompt("New Event name");
alert("title " + title);
if (title) {
// add a new event
setEvents(events => ([
...events,
{
start,
end,
title
}
]))
// setState is async, outputting the events here will most likely return the old value
console.log(events);
}
};
return (
<div>
<Navigation />
<Calendar
selectable
localizer={localizer}
events={events}
popup
startAccessor="start"
endAccessor="end"
style={{ height: 700 }}
onSelectSlot={handleSelect}
/>
</div>
)
};
export default MyCalendar;

Trigger rerender after setTimeout in react

I am trying to get my head around React, and I am doing some projects. One of them involving rerendering a component after a variable changes after setTime out runs out.
I am supposing it has to rerender, since it changes after the initial render ( and that it doesn't react (heh) the the updated variable.
I am guessing I am misunderstanding some React fundamentals here.
Arrows to highligt my problem.
Component:
import React from 'react';
import classes from './Navigation.module.css';
const navigation = (props) => {
let attachedClasses = [classes.SmallDot];
let showCloseButton = false; <-------!
if (props.currentState) {
attachedClasses = [classes.BigDot]
setTimeout(() => {
showCloseButton = true; <----------!
}, 500)
}
return (
<div onClick={props.currentState ? null : props.toggleMenuState} className={attachedClasses.join(' ')}>
{showCloseButton ? <--------!
<div onClick={props.toggleMenuState} className={classes.CloseButton}>
<div>X</div>
</div>
: null}
</div>
)
};
export default navigation;

How to simulate mouse over event on a div using enzyme for testing a react application?

I have a div that onMouseOver and onMouseLeave toggles a child div as a dropdown. I want to test the hover event using enzyme.
The relevant code for the component is:
<div className="search-category" onMouseOver={() => toggleDropdown(true)} onMouseLeave={() => toggleDropdown(false)}>
<div className="search-type">
...
</div>
{dropdownShown && <SearchMenu searchSections={searchSections} dispatch={dispatch} />}
</div>
The relevant test code is
...
it('should toggle search type dropdown on mouse hover', () => {
expect(enzymeWrapper.find('.SearchMenu').exists()).toEqual(false);
enzymeWrapper.find('.search-category').simulate('mouseOver');
expect(enzymeWrapper.find('.SearchMenu').exists()).toEqual(true);
});
...
.SearchMenu is the className of the SearchMenu component.
toggleDropdown is a simple function that toggles the dropdownShown flag.
The issue i'm facing is that even after calling .simulate, the expect on the last line returns false when it should return true. The code is working perfectly as I can see the dropdown on the browser and in the element tab of the browser.
Please let me know if any more details are required.
Any help would be highly appreciated.
If I have replicated your issue correctly, here is the working demo, of the test cases you were trying to run. I have written a number of test cases using enzyme and jest, and I think this is the right way to do the testing. :)
Toggle.js
import React from "react";
export const SearchMenu = () => <input />;
class Toggle extends React.Component {
state = { dropdownShown: true };
toggleDropdown = value => {
this.setState({ dropdownShown: value });
};
render() {
return (
<div
className="search-type"
onMouseOver={() => this.toggleDropdown(true)}
onMouseLeave={() => this.toggleDropdown(false)}
>
<h1>Hover over me to hide/unhide the input</h1>
{this.state.dropdownShown && <SearchMenu />}
</div>
);
}
}
export default Toggle;
Toggle.spec.js
import React from "react";
import { shallow } from "enzyme";
import Toggle from "./Toggle";
import Enzyme from "enzyme";
import { SearchMenu } from "./Toggle";
describe("Toggle Component", () => {
it("check state", () => {
const wrapper = shallow(<Toggle />);
expect(wrapper.find(<SearchMenu />).exists).toBeTruthy();
// Testing Initial State
expect(wrapper.state("dropdownShown")).toBe(true);
wrapper.simulate("mouseleave");
// Testing state after mouseleave
expect(wrapper.state("dropdownShown")).toBe(false);
// Testing state after mouseover
wrapper.simulate("mouseover");
expect(wrapper.state("dropdownShown")).toBe(true);
});
});
Chasing Unicorn's answer above is almost perfect. Instead of passing mouseover to wrapper.simulate, it should be mouseenter.
This worked for me:
it('sets hoveredOver state to true/fase from mouseenter and mouseleave events', () => {
const wrapper = shallow(<MyComponent {...defaultProps} />);
// initial state:
expect(wrapper.state('hoveredOver')).toBe(false);
wrapper.simulate('mouseenter');
expect(wrapper.state('hoveredOver')).toBe(true);
wrapper.simulate('mouseleave');
expect(wrapper.state('hoveredOver')).toBe(false);
});
This is with Enzyme v3.3.0 in my package.json

Categories

Resources