我整天都被困在这里,希望得到一些帮助。预先感谢。
起初我是这样写的,但是会出现一个类型错误:todos.map不是函数。
function toggleState() {
setTodos(state => ({ ...state, isComplete: !state.isComplete }))
}
最后,我意识到错误是因为它以待办事项作为对象返回,所以我尝试了这一点:
function toggleState() {
setKeywords(state => [{ ...state, isUsed: !state.isUsed }])
}
现在我没有收到类型错误,但是仍然无法按预期工作。这是toggleState之前的状态:
[
{
"name": "State",
"value": [
{
"todo": "Learn React",
"id": "91bad41d-1561-425a-9e77-960f731d058a",
"isComplete": false
}
]
,这是之后的状态:
[
{
"name": "State",
"value": [
{
"0": {
"todo": "Learn React",
"id": "91bad41d-1561-425a-9e77-960f731d058a",
"isComplete": false
},
"isComplete": true
}
]
这是我其余的代码:
import React, { useState, useEffect } from 'react'
import { uuid } from 'uuidv4'
import { Form, FormGroup, Input, Button } from 'reactstrap'
function Example(props) {
const [todos, setTodos] = useState([])
// Run when component first renders
useEffect(() => {
console.log('useEffect component first rendered')
if (localStorage.getItem('todoData')) {
setTodos(JSON.parse(localStorage.getItem('todoData')))
}
}, [])
// Run when todos state changes
useEffect(() => {
console.log('useEffect todos changed')
localStorage.setItem('todoData', JSON.stringify(todos))
}, [todos])
const [formInput, setFormInput] = useState()
function handleChange(e) {
setFormInput(e.target.value)
}
function handleSubmit(e) {
e.preventDefault()
setTodos(prev => prev.concat({ todo: formInput, id: uuid(), isComplete: false }))
setFormInput('')
}
function toggleState() {
setTodos(state => [{ ...state, isComplete: !state.isComplete }])
}
return (
<div className='text-center'>
<div className='mb-2 border text-center' style={{ height: '300px', overflowY: 'scroll' }}>
{todos.map(todo => (
<p className={todo.isUsed ? 'text-success my-1' : 'text-danger my-1'} key={todo.id}>
{todo.todo}
</p>
))}
</div>
<Form onSubmit={handleSubmit}>
<FormGroup>
<Input onChange={handleChange} type='text' name='text' id='todoForm' placeholder='Enter a todo' value={formInput || ''} />
<Button>Set Todo</Button>
</FormGroup>
</Form>
<Button onClick={toggleState}>Toggle isComplete</Button>
</div>
)
}
export default Example
答案 0 :(得分:1)
我最终使用的方法(已经见过其他开发人员)是先复制对象或状态,对其进行修改,然后使用修改后的状态设置新状态。
我还注意到您需要为待办事项提供索引以便能够切换它们,因此我添加了该功能。
看一个工作示例,单击下面的“运行代码段” 。
A
// main.js
// IGNORE THIS BECAUSE THIS IS JUST TO USE REACT IN STACK OVERFLOW
const { useEffect, useState } = React;
// ---- CODE STARTS HERE -----
const Example = (props) => {
const [todos, setTodos] = useState([]);
const [formInput, setFormInput] = useState('');
// Run when component first renders
useEffect(() => {
/*
// Uncomment - Just doesn't work in Stack Overflow
if (localStorage && localStorage.getItem('todoData')) {
setTodos(JSON.parse(localStorage.getItem('todoData')));
}
*/
}, []);
// Hooks
const handleChange = event => {
setFormInput(event.target.value);
};
const handleSubmit = event => {
const newTodosState = [...todos ]; // make copy
newTodosState.push({ todo: formInput, isComplete: false });
setTodos(newTodosState);
// Add functionality to update localStorage
// ex:
// localStorage.setItem('todoData', newTodosState);
// Reset form
setFormInput('');
event.preventDefault();
};
const toggleTodoState = index => event => {
const newTodosState = [...todos ]; // make copy
newTodosState[index].isComplete = !newTodosState[index].isComplete;
setTodos(newTodosState);
// Add functionality to update localStorage
};
const handleDelete = index => event => {
const newTodosState = [...todos.slice(0, index), ...todos.slice(index + 1) ];
setTodos(newTodosState);
// Add functionality to update localStorage
}
// Render
return (<div>
<h3>Todos</h3>
<ul>
{todos.map((item, index) => <li key={`todo-${index}`}>{item.todo} - <input type="checkbox" checked={item.isComplete} onClick={toggleTodoState(index)} /> - <button onClick={handleDelete(index)}>Delete</button></li>)}
</ul>
<hr />
<form onSubmit={handleSubmit}>
<input type="text" value={formInput} onChange={handleChange} placeholder="Enter todo name" />
<button type="submit">Add</button>
</form>
</div>);
};
ReactDOM.render(<Example />, document.querySelector('#root'));
答案 1 :(得分:1)
因此,在您的特定情况下,您只想在第一项上切换isComplete
,可以这样实现:
function toggleState() {
setTodos(([firstItem, ...remainder]) => {
return [
{
...firstItem,
isComplete: !firstItem.isComplete
},
...remainder
];
});
}
在其中使用解构分配来获取FirstItem并对其进行操作,然后将提醒传播回状态。