#javascript #reactjs
#javascript #reactjs
Вопрос:
У меня есть простая структура todolist для состояния компонента. Это массив с двумя полями, называемыми ‘content’, и одним, называемым ‘done’. Я перехватываю щелчок элемента строки с помощью простой функции onClick (), передаваемой от родительского элемента к дочернему элементу TodoItem (как предлагает руководство по React):
render() {
const tthis = this;
var myList = tthis.state.todos.map(function(todo,index){
var myOnCLick = function(){
var newTodo = {content: todo.content, done: !todo.done};
tthis.state.todos[index] = newTodo;
tthis.setState({});
}
return <Todo key={index} todo={todo} onClick={myOnCLick}/>
})
return (
<ul className="list">
{ myList }
</ul>
)
}
Этот код работает без проблем, но мне это не очень нравится.
Я бы нашел какое-нибудь хорошее решение для изменения значения одного элемента в массиве. Я обнаружил, что в помощнике по неизменяемости React DOC:
{$set: any} полностью замените цель.
И в хорошем ответе на этом форуме я видел пример:
this.setState({
todos: update(this.state.todos, {1: {done: {$set: true}}})
Но я не могу использовать 1 в моем случае. У меня есть индекс, который дает мне индекс нажатой задачи в списке задач.
Ответ №1:
Вы можете изменить значение done
свойства для отдельного объекта todo, перечисленного в массиве, следующим образом:
flipDone(id) {
let index = Number(id);
this.setState({
todos: [
...this.state.todos.slice(0, index),
Object.assign({}, this.state.todos[index], {done: !this.state.todos[index].done}),
...this.state.todos.slice(index 1)
]
});
}
Вот демонстрация:http://codepen.io/PiotrBerebecki/pen/jrdwzB
Полный код:
class TodoList extends React.Component {
constructor() {
super();
this.flipDone = this.flipDone.bind(this);
this.state = {
todos: [
{content: 'Go shopping', done: false},
{content: 'Walk the dog', done: false},
{content: 'Wash the dishes', done: false},
{content: 'Learn React', done: false}
]
};
}
flipDone(id) {
let index = Number(id);
this.setState({
todos: [
...this.state.todos.slice(0, index),
Object.assign({}, this.state.todos[index], {done: !this.state.todos[index].done}),
...this.state.todos.slice(index 1)
]
});
}
render() {
const myList = this.state.todos.map((todo, index) => {
return (
<Todo key={index}
clickHandler={this.flipDone}
content={todo.content}
done={todo.done}
id={index}
/>
);
})
return (
<ul className="list">
{myList}
</ul>
);
}
}
class Todo extends React.Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.props.clickHandler(event.target.id);
}
render() {
return (
<li>
<button onClick={this.handleClick}
id={this.props.id}>
Click me
</button> ---
{String(this.props.done)} ---
{this.props.content}
</li>
);
}
}
ReactDOM.render(
<TodoList />,
document.getElementById('app')
);
Комментарии:
1. Хотите, чтобы я что-нибудь добавил к вышесказанному или это отвечает на ваш вопрос?
2. Я никогда не использовал синтаксис из трех точек. Ваше решение отлично работает, но все элементы в списке вызывают render каждый раз 🙂
3.Синтаксис из трех пунктов называется оператором распространения. Например:
let cold = ['autumn', 'winter'];
let warm = ['spring', 'summer'];
console.log([...cold, ...warm])
=>['autumn', 'winter', 'spring', 'summer']
Больше информации здесь: developer.mozilla.org/en/docs/Web/JavaScript/Reference /…