#javascript #arrays #reactjs
#javascript #массивы #reactjs
Вопрос:
Пожалуйста, помогите мне с этим, я не совсем понимаю, где именно я делаю неправильно. Поэтому, когда я нажимаю на флажок, значения не меняются (если это по умолчанию true
, когда я нажимаю на щелчок, он должен false
быть). Для этого onChange
в todoList
компоненте in я вызываю handleClick
функцию, там я меняю todo.completed
значение (в основном переключая значения).
App.js
Внутри handleClick
метода, когда do console.log(todo)
перед возвратом из функции map значение переключается нормально, но оно не обновляется в updatedTodo
.
App.js
import TodosData from "./todoData";
import TodoList from "./todoList";
import "./styles.css";
class App extends Component {
constructor() {
super();
this.state = {
todos: TodosData
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(id) {
this.setState(prevState => {
const updatedTodo = prevState.todos.map(todo => {
// console.log(updatedTodo);
if(todo.id === id) {
console.log("before the opt " todo.completed);
todo.completed = !todo.completed
console.log("after the opt " todo.completed);
}
//console.log(todo);
return todo;
})
console.log(updatedTodo);
return {
todos: updatedTodo
}
});
}
render() {
const todoDataComponents = this.state.todos.map(item => {
return <TodoList key = {item.id} item = {item} handleChange = {this.handleChange} />
})
return (
<div className="todo-list">{todoDataComponents}</div>
);
}
}
export default App;
Список задач.jsx
class TodoList extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
// console.log(this.props)
return (
<div className="todo-item">
<input
type="checkbox"
checked={this.props.item.completed}
onChange = {() => this.props.handleChange(this.props.item.id)}
/>
<p>{this.props.item.text}</p>
</div>
);
}
}
export default TodoList;
todoData.js
const TodosData = [
{ id: 1, text: "Coding", completed: true },
{ id: 2, text: "Exercise", completed: false },
{ id: 3, text: "Learning", completed: true },
{ id: 4, text: "Programming", completed: true },
{ id: 5, text: "inspire", completed: false },
{ id: 6, text: "motivation", completed: true }
];
export default TodosData;
Ответ №1:
Я не вижу никаких ошибок в вашем handleChange()
методе, он должен работать нормально. Однако я только что обновил часть вашего кода, который вы можете протестировать ниже.
Я изменил ваше название TodoList
, так как на самом деле это не список, а элемент. Я также изменил его на функциональный компонент, поскольку он является только презентационным, нет необходимости иметь собственное состояние. Вместо того чтобы добавлять p
тег после input
, вы должны использовать a label
, чтобы сделать его доступным.
Я на самом деле ничего не изменил в вашем handleChange()
методе, только удалил console.log
s, и он работает так, как ожидалось.
Обновление: вы используете React.StrictMode
, где React отображает все дважды в dev. Поскольку ваш handleChange()
запуск completed
выполняется дважды, он дважды устанавливает состояние нажатой задачи, возвращая ее в исходное состояние. Поэтому, если он false
включен при первом рендеринге, он устанавливается на true
on click, но он снова отображается, а на втором возвращается false
. Вы не заметите этого, так как это происходит довольно быстро.
Чтобы избежать этого, вам нужно избегать каких-либо изменений. Итак, я обновил ваш onChange
обработчик, он возвращает новый объект, если completed
свойство изменено.
Не стесняйтесь запускать фрагмент кода ниже и нажимать на флажки или тексты элементов.
const TodosData = [
{ id: 1, text: 'Coding', completed: true },
{ id: 2, text: 'Exercise', completed: false },
{ id: 3, text: 'Learning', completed: true },
{ id: 4, text: 'Programming', completed: true },
{ id: 5, text: 'Inspire', completed: false },
{ id: 6, text: 'Motivation', completed: true },
];
function TodoItem(props) {
const { handleChange, item } = props;
return (
<div className="todo-item">
<input
type="checkbox"
id={`item-${item.id}`}
checked={item.completed}
onChange={() => handleChange(item.id)}
/>
<label htmlFor={`item-${item.id}`}>{item.text}</label>
</div>
);
}
class App extends React.Component {
constructor() {
super();
this.state = {
todos: TodosData,
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(id) {
this.setState((prevState) => {
const updatedTodo = prevState.todos.map((todo) => {
return todo.id === id ? {
...todo,
completed: !todo.completed,
} : todo;
});
return {
todos: updatedTodo,
};
});
}
render() {
const { todos } = this.state;
return (
<div className="todo-list">
{todos.map((item) => (
<TodoItem
key={item.id}
item={item}
handleChange={this.handleChange}
/>
))}
</div>
);
}
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
body {
font-family: sans-serif;
line-height: 1.6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Ответ №2:
Вместо того чтобы использовать дополнительную переменную, вы можете сделать это в одной строке. Можете ли вы посмотреть, работает ли это для вас.
handleChange(id) {
this.setState(prevState => prevState.map(todo => todo.id === id ? {...todo, completed: !todo.completed} : todo )
}
Комментарии:
1. Привет, @Кто-то, у меня это не работает. Я попытался с помощью `handleChange (id) { this.setState (prevState => prevState.todos.map(todo => todo.id === идентификатор? {…todo, завершено: !todo.завершено}: todo )) }` вы можете проверить мой код в [link] ( codesandbox.io/s/recttodo-cmbqz?file=/src/App.js:314-617 )