ReactJS - How to toggle button that got clicked? - javascript

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;

Related

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>
)

How to call a prop function inside useEffect?

Im triying to remove this warning on a react component
Line 19:8: React Hook useEffect has a missing dependency: 'handleChange'. Either include it or remove the dependency array react-hooks/exhaustive-deps
this is the component
const SelectButton = (props)=>{
const [activeState, setActiveState] = useState(false)
const label = props.label
const handleClick = () =>{
setActiveState(!activeState)
//props.handleChange(label,activeState)
}
const handleChange = props.handleChange
useEffect(()=>{
handleChange(label,activeState)
}, [label,activeState])
return(
<button
type="button"
onClick={handleClick}
className={"container-form-button "+(activeState?"active":"")}>
{label}
</button>
)
}
if i tried to remove the comments on handleChange inside of handleClick, handleChange didn´t works correctly
if i tried to change useEffect for something like this
useEffect(()=>{
handleChange(label,activeState)
}, [label,activeState,handleChange])
or
useEffect(()=>{
props.handleChange(label,activeState)
}, [label,activeState,props.handleChange])
it try to reder to many times and throw this error.
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render
Actually it works like first code, but im still having the warning
this is the parent original handleChange
const handleChange = (name,value)=>{
setSelected({...selected, [name]:value})
}
the parentComponent
const CategorySearcher = (props) =>{
const ciudades = ["Guadalajara","Zapopan","Tlajomulco"]
const tipos = ["Casa","Departamento"]
const [selected, setSelected] = useState({})
const handleChange = useCallback(
(label,value) => {
setSelected({...selected, [label]:value})
},
[selected],
)
useEffect(() => {
console.log(selected);
}, [selected])
const cities = ciudades.map((city)=><SelectButton key={city} handleChange={handleChange} label={city}/>)
const types = tipos.map((tipo)=><SelectButton key={tipo} handleChange={handleChange} label={tipo}/>)
let history = useHistory();
const setUrlSearch = ()=>{
let urlSearch = "search/q="
let attToSearch = []
for (var key in selected) {
selected[key]?attToSearch.push(key):console.log("Nada")
}
/*
attToSearch.forEach((it)=>{
urlSearch = urlSearch+"&"+it
})*/
console.log(urlSearch);
history.push(urlSearch+attToSearch)
}
return (
<section className="general-container">
<div className="container-box">
<span className="container_title">
Tu nuevo hogar esta aquí :)
</span>
</div>
<div className="container-form">
<form className="container-form-box">
<div className="container-form-cities">
<div className="container-form-subtitle">
Ciudades
</div>
<div className="container-buttons">
{cities}
</div>
</div>
<div className="container-form-cities">
<div className="container-form-subtitle">Tipo de hogar</div>
<div className="container-buttons">
{types}
</div>
</div>
<div className="container-box-button">
<button className="button-form-CTA" onClick={setUrlSearch}>
Buscar
</button>
</div>
</form>
</div>
</section>
)
}
You should be wrapping your function with the useCallback hook before passing it as a prop. Documentation can be found here.
You shouldn't be using useEffect like that.
const SelectButton = ({ label, handleChange }) => {
const [activeState, setActiveState] = React.useState(false);
const handleClick = () => {
const newState = !activeState
setActiveState(newState);
handleChange(label, newState);
};
return (
<button
type="button"
onClick={handleClick}
className={"container-form-button " + (activeState ? "active" : "")}
>
{label}
</button>
);
};
Why don't you destructure label and handleChange from props? Check out this sandbox, this does not cause any infinite update loop: codesandbox
import React from "react";
export default function App() {
const handleChange = () => console.log("handling change");
return (
<div className="App">
<SelectButton label="Label" handleChange={handleChange} />
</div>
);
}
const SelectButton = ({ label, handleChange }) => {
const [activeState, setActiveState] = React.useState(false);
const handleClick = () => {
setActiveState(!activeState);
};
React.useEffect(() => {
handleChange(label, activeState);
}, [label, activeState, handleChange]);
return (
<button
type="button"
onClick={handleClick}
className={"container-form-button " + (activeState ? "active" : "")}
>
{label}
</button>
);
};

How can I toggle between 3 components in ReactJS

I am having a hard time rendering components conditionally in React. I have successfully rendered 2 components (A and B) conditionally but couldn't find any successful way to add a third component (C) in our case
this is the code for 2 componnets:
function App() {
const [click, setClick] = useState(true);
const ShowA = () => setClick(true);
const ShowB = () => setClick(false);
return (
<>
<br />
<button onClick={ShowA}>A </button>
<button onClick={ShowB}>B </button>
<div className="App">
{click && <div> A </div>}
{!click && <div>B</div>}
</div>
</>
);
}
Is there any possible way I can add a third C component so I can toggle between them? I have been trying for 2 days but no success.
This is the link of Codesandbox if anyone's interested
https://codesandbox.io/s/musing-tesla-9gkpw?file=/src/index.js:100-481
You can put as many states as you want:
function App() {
const [displayA, setDisplayA] = useState(true);
const [displayB, setDisplayB] = useState(true);
const [displayC, setDisplayC] = useState(true);
const showA = () => {
setDisplayA(true);
setDisplayB(false);
setDisplayC(false);
}
const showB = () => {
setDisplayA(false);
setDisplayB(true);
setDisplayC(false);
};
const showC = () => {
setDisplayA(false);
setDisplayB(false);
setDisplayC(true);
};
return (
<>
<br />
<button onClick={showA}>A</button>
<button onClick={showB}>B</button>
<button onClick={showC}>C</button>
<div className="App">
{displayA && <div>A</div>}
{displayB && <div>B</div>}
{displayC && <div>C</div>}
</div>
</>
);
}
And you can even put other things in your state, like JSX elements:
function App() {
const [elementToDisplay, setElementToDisplay] = useState("");
const showA = () => {
setElementToDisplay(<div>A</div>)
}
const showB = () => {
setElementToDisplay(<div>B</div>)
}
const showC = () => {
setElementToDisplay(<div>C</div>)
}
return (
<>
<br />
<button onClick={showA}>A</button>
<button onClick={showB}>B</button>
<button onClick={showC}>C</button>
<div className="App">
{elementToDisplay}
</div>
</>
);
}
You can save a state for the current button, and then show the different button conditionally using object lookup:
Check https://codesandbox.io/s/kind-haslett-b0fv0
function App() {
const [currentButton, setCurrentButton] = useState('A');
return (
<>
<br />
<button onClick={() => setCurrentButton('A')}>A</button>
<button onClick={() => setCurrentButton('B')}>B</button>
<button onClick={() => setCurrentButton('C')}>C</button>
<div className="App">
{
({
A: <div>A</div>,
B: <div>B</div>,
C: <div>C</div>
})[currentButton]
}
</div>
</>
);
}

Is it possible to pass setValue in react to child componenet as a function

I have the following setup in react, now it complains that setClose is not a function inside the add to cart. I am stuck as to how I would trigger the setclose useState from inside the add to cart componenet, I guess I can't pass it as a prop down to the child. Not sure what to do at this point.
Thanks ahead of time
main component
const [close, setClose] = useState(true)
const toggleCart = () => {
setClose(!close)
}
return (
<AddToCart
cartAdd={setClose}
/>
{close ? <CartItems /> : null}
)
add to cart componenet
import React from "react"
import { useShoppingCart, formatCurrencyString } from "use-shopping-cart"
const AddToCart = ({ sku, setClose }) => {
const { addItem } = useShoppingCart()
const test = () => {
setClose(false)
}
return (
<div>
<button onClick={(() => addItem(sku), test())}>ADD TO CART</button>
</div>
)
}
export default AddToCart
const [close, setClose] = useState(true)
const toggleCart = () => {
setClose(!close)
}
return (
<AddToCart
cartAdd={toggleCart}
/>
{close ? <CartItems /> : null}
)
const AddToCart = ({ sku, cartAdd }) => {
const { addItem } = useShoppingCart()
const handleButtonClick = () => {
addItem(sku);
cartAdd();
}
return (
<div>
<button onClick={handleButtonClick}>ADD TO CART</button>
</div>
)
}
use like this
UPDATED

Categories