I want to change the class of a component when clicked.I use state to create a new component with the properties of name and done(which is upon creation false).Then this is pushed into the todos array. Now the question is how do I find which component is clicked and change its "done" property to?done ?
function App() {
const [todos, setTodos] = useState([])
const [newTodo, setNewTodo] = useState({
name: "",
done: false
})
const handleInput = (event) => {
setNewTodo({name: event.target.value})
}
const handleDone = (event) => {
//WHAT TO DO HERE
}
const submitTodo = (event) => {
event.preventDefault();
setTodos([...todos, newTodo.name])
console.log(newTodo.name)
setNewTodo({name: ""})
}
return (
<div className="App">
<form onSubmit={submitTodo}>
<input onChange={handleInput} value={newTodo.name}/>
<button>Add Todo!</button>
</form>
<ul>
{todos.map(todo => (
<li className={/*Change the class based on the DONE property*/} onClick={handleDone}>{todo}</li>
))}
</ul>
</div>
);
}
export default App;
change your newTodo state
const [newTodo, setNewTodo] = useState('');
const [show,setShow] = useState(false);
const handleDone = (event) => setShow(!show)
.....
.....
.....
<li className={show ? 'classname when show is true': 'classname when show is false'} onClick={handleDone}>{todo}</li>
First of all, you should consistently make your todos contain both name
and done
properties. Having this you just pass the todo from the clicked <li>
to your click handler so it can modify its done property and cause rerender by updating todos
state.
function App() {
const [todos, setTodos] = useState([])
const [newTodo, setNewTodo] = useState({
name: "",
done: false
})
const handleInput = (event) => {
setNewTodo({name: event.target.value, done: false }); // this now adds done property
}
const handleDone = (todo) => {
todo.done = !todo.done;
setTodos([...todos]); // This sets new todos to cause a rerender with updated list
}
const submitTodo = (event) => {
event.preventDefault();
setTodos([...todos, newTodo]) // this now appends entire newTodo item not only it's name
setNewTodo({name: "", done: false}) // this now also sets default done
}
return (
<div className="App">
<form onSubmit={submitTodo}>
<input onChange={handleInput} value={newTodo.name}/>
<button>Add Todo!</button>
</form>
<ul>
{todos.map(todo => (
<li
className={todo.done ? 'classA' : 'classB'}
onClick={() => handleDone(todo)}
>
{todo.name} // this now displays todo.name not todo
</li>
))}
</ul>
</div>
);
}
export default App;
Additionally you could extract todos and the click handler into a separate component:
function ToDo({ item }) {
const [clicked, setClicked] = useState(item.done);
const handleClick = useCallback(() => {
item.done = !clicked
setClicked(!clicked);
}, [clicked]);
return <li
className={clicked ? 'classA' : 'classB'}
onClick={handleClick}
>
{item.name}
</li>;
}
Then just render a list of components with your App component:
<ul>
{todos.map(todo => <ToDo item={todo} />
</ul>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.