ReactJS onclick toggle class event multiple times - javascript

How can I use this onclick toggle class event multiple times?
const [isActive, setActive] = React.useState(false);
<button
onClick={() => setActive(!isActive)}
className={`toggle ${isActive ? "active" : ""}`}
>
Categories
</button>
Here is the issue in Sandbox: https://codesandbox.io/s/agitated-pond-tewk9h?file=/src/App.js
When click on any button it works for all others.

You should create a component for your button that contains the useState.
Else, the useState is global for all the components that use it.
Example:
https://codesandbox.io/s/withered-feather-vj8owx?file=/src/App.js
const MyButtonComponent = ({myText}) => {
const [isActive, setActive] = React.useState(false);
return (
<button
onClick={() => setActive(!isActive)}
className={`toggle ${isActive ? "active" : ""}`}
>
{myText}
</button>
);
};
export default function App() {
return (
<>
<MyButtonComponent myText="Something" />
<MyButtonComponent myText="Something else"/>
<MyButtonComponent myText="Else something"/>
</>
);
}

This is for reference:
Edited answer from Magofoco
Passing button text & ID:
const MyButtonComponent = ({ myText, myId }) => {
const [isActive, setActive] = React.useState(false);
return (
<Button
onClick={() => setActive(!isActive)}
className={`toggle ${isActive ? "active" : ""}`}
id={myId}
>
{myText}
</Button>
);
};
export default function App() {
return (
<MyButtonComponent myText="something" myId="tab01" />
);
}

Related

How to write a test in Jest for onClick function?

I have a React component and I would like to write a test to see if onClick renders properly when clicked title div.
I tried to do this with userEvent, but it is not working, not sure where there is a mistake.
Here is a piece of code:
const DropDown = ({ children, text, color, activeColor }) => {
const [isActive, setIsActive] = useState(false)
return (
<Styled.DropDown color={color}>
<Styled.Title
variant="h5"
as="div"
onClick={() => setIsActive(!isActive)}
color={isActive ? activeColor : color}
>
{text}
<Styled.Icon isActive={isActive}>
<Icon name="arrowUp" />
</Styled.Icon>
</Styled.Title>
{isActive && <Styled.Content>{children}</Styled.Content>}
</Styled.DropDown>
)
}
and the test I tried to write:
it(`fires onClick callback when accordion is clicked`, () => {
const onClickMock = jest.fn()
render(<DropDown onClick={onClickMock} />)
const link = screen.getByRole("link")
act(() => {
userEvent.click(link)
})
expect(onClickMock).toBeCalledTimes(1)
})

How to call from outside a hook in a component included by another component?

I have a very basic react component like this
const Message = (props) => {
const [show, setShow] = useState(false);
return (
<p show={show}>My Message</p>
);
};
I want to use this component from another one, and I want to be able to show the first one by clicking on a button in the second one
const OtherComponent = (props) => {
return (
<>
<Message />
<Button onClick={setShow(true)}>Open Message</Button>
</>
);
};
of course this code does not work, is there a way to achieve this or is Redux my only option?
Move state to parent
const Message = ({ show }) => {
return (
<p show={show}>My Message</p>
);
};
const OtherComponent = (props) => {
const [show, setShow] = useState(false);
return (
<>
<Message show={show} />
<Button onClick={setShow(true)}>Open Message</Button>
</>
);
};

How to make other button functions automatically run when a button is clicked

I clicked the Button and executed the onClickUserId function.
Then, if I run this function, I want to run the onClickListContent Button function as well.
I don't know what to do.
I want to display the argument value in the console.log so that onClickListContent is automatically clicked when the onClickUserId value is clicked.
const onClickUserId = (id) => {
console.log(id)
}
const onClickListContent = (Content) => {
console.log(Content);
};
return (
<div>
<>
<div>
<button onClick={() => onClickUserId(3)}>click</button>
</div>
</>
<>
<div>
<button onClick={() => onClickListContent(6)}>click</button>
</div>
</>
</div>
)
I tried to put the onClickListContent.click() function in the onClickUserId function, but it cannot be executed because of the argument value.
How should I write the code?
import {useRef} from 'react'
export default function App() {
const ref = useRef()
const onClickUserId = (id) => {
console.log(id);
ref.current.click();
};
const onClickListContent = (Content) => {
console.log(Content);
};
return (
<div>
<>
<div>
<button onClick={() => onClickUserId(3)}>click</button>
</div>
</>
<>
<div>
<button ref={ref} onClick={() => onClickListContent(6)}>click</button>
</div>
</>
</div>
);
}
you can create a reference to that button and use it trigger the click function.
use react useRef() hook:
const listContentBtn = useRef(null);
const onClickUserId = (id) => {
console.log(id)
listContentBtn.current.click()
}
const onClickListContent = (Content) => {
console.log(Content);
};
return (
<div>
<>
<div>
<button onClick={() => onClickUserId(3)}>click</button>
</div>
</>
<>
<div>
<button onClick={() => onClickListContent(6)} ref={listContentBtn}>click</button>
</div>
</>
</div>
)

React : Open/close react-colorful picker

I'm using react-colorful to get colors HEX code.
I would want to show this component when the color's box is clicked, and hide it when clicked outside of it, kinda like the color picker Chrome is using (ex <input type="color" /> )
How to do so ?
https://codesandbox.io/s/react-colorful-demo-forked-wwxq2?file=/src/App.js:308-322
import React, { useState } from "react";
import { HexColorPicker } from "react-colorful";
import "./styles.css";
export default function App() {
const [color, setColor] = useState("#b32aa9");
const handleChange = (e) => {
setColor(e.target.value);
};
return (
<div className="App">
<HexColorPicker color={color} onChange={setColor} />
//Click on this box to show the picker <div className="value" style={{ borderLeftColor: color }}>
Current color is {color}
</div>
<input value={color} onChange={handleChange} />
<div className="buttons">
<button onClick={() => setColor("#c6ad23")}>Choose gold</button>
<button onClick={() => setColor("#556b2f")}>Choose green</button>
<button onClick={() => setColor("#207bd7")}>Choose blue</button>
</div>
</div>
);
}
At first, you should have to declare a state which tracks whether the color box is open or not like
const [open, setopen] = useState(false);
Now add an event handler on the div of the box which toggles the state from false to true and true to false.
const openBox = () => {
setopen(!open);
}
Now in your return statement, add a conditional to open or close colorBox. if clicked on that div which holds the onClick method.
<div className="App">
{open &&<HexColorPicker color={color} onChange={setColor} />
}
<div onClick={() => openBox()}className="value" style={{ borderLeftColor: color }}>
Current color is {color}
</div>
Now if you click on the div which contains the onClick method, it will open the colorBox and on pressing again it will close it.
You can use the following example (from https://codesandbox.io/s/opmco found in Code Recipes)
import React, { useCallback, useRef, useState } from "react";
import { HexColorPicker } from "react-colorful";
import useClickOutside from "./useClickOutside";
export const PopoverPicker = ({ color, onChange }) => {
const popover = useRef();
const [isOpen, toggle] = useState(false);
const close = useCallback(() => toggle(false), []);
useClickOutside(popover, close);
return (
<div className="picker">
<div
className="swatch"
style={{ backgroundColor: color }}
onClick={() => toggle(true)}
/>
{isOpen && (
<div className="popover" ref={popover}>
<HexColorPicker color={color} onChange={onChange} />
</div>
)}
</div>
);
};
useClickOutside.js
import { useEffect } from "react";
// Improved version of https://usehooks.com/useOnClickOutside/
const useClickOutside = (ref, handler) => {
useEffect(() => {
let startedInside = false;
let startedWhenMounted = false;
const listener = (event) => {
// Do nothing if `mousedown` or `touchstart` started inside ref element
if (startedInside || !startedWhenMounted) return;
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) return;
handler(event);
};
const validateEventStart = (event) => {
startedWhenMounted = ref.current;
startedInside = ref.current && ref.current.contains(event.target);
};
document.addEventListener("mousedown", validateEventStart);
document.addEventListener("touchstart", validateEventStart);
document.addEventListener("click", listener);
return () => {
document.removeEventListener("mousedown", validateEventStart);
document.removeEventListener("touchstart", validateEventStart);
document.removeEventListener("click", listener);
};
}, [ref, handler]);
};
export default useClickOutside;

ReactJS - How to toggle button that got clicked?

I'm new in React, I don't know what keyword to find my solution. I have many <button> and just want to toggle the button that got clicked. How to achieve that?
Here's what i've been trying...
export default function App() {
const [text, setText] = useState(false);
const btnText = text ? 'Foo' : 'Bar';
const handleClick = () => setText((prevState) => !prevState);
return (
<div className="App">
<button type="button" onClick={handleClick}>{btnText}</button>
<button type="button" onClick={handleClick}>{btnText}</button>
<button type="button" onClick={handleClick}>{btnText}</button>
</div>
);
}
Add unique id on each buttons, and you can change your code like this:
export default function App() {
const listOfButtons = [0, 1, 2];
const [btnClicked, setBtnClicked] = useState([]);
const handleClick = (id) => setBtnClicked({...btnClicked, [id]: !btnClicked[id]});
return (
<div className="App">
{listOfButtons.map(id => (
<button type="button" onClick={() => handleClick(id)}>{`${btnClicked[id] ? 'clicked' : 'not clicked'}`}</button>
))}
</div>
);
}
When you pass a function without the parens, you're just passing the definition. In your onClick, invoke your function like this:
onClick={()=>handleClick()}
if you were to invoke the handleClick function w/o it being inside an arrow function, then you would get an infinite loop.
onClick={handleClick()}
export default function App() {
//each button needs its own state
const [text, setText] = React.useState({
button234423: false,
button456645: false,
button398375: false
});
//target button in state by element id
const handleClick = e => {
const id = e.target.id;
setText(text => ({ ...text, [id]: !text[id] }));
};
//map state to return button element with key as id and value as conditional
return (
<div className="App">
{Object.entries(text).map(([key, value]) => {
return (
<button type="button" key={key} id={key} onClick={handleClick}>
{value ? "Foo" : "Bar"}
</button>
);
})}
</div>
);
}
Currently state shared to all the button. Keep it as a separate component
import './App.css';
function App() {
return (
<div className="App">
<Button />
<Button />
<Button />
</div>
);
}
export const Button = () => {
const [text, setText] = useState(false);
const btnText = text ? 'Foo' : 'Bar';
const handleClick = () => setText((prevState) => !prevState);
return <button type="button" onClick={handleClick}>{btnText}</button>
}
export default App;

Categories