#javascript #reactjs
#javascript #reactjs
Вопрос:
я очень новичок в React, просто хотел создать простую программу с несколькими кнопками, которые соответствуют некоторому значению в state, я хочу, чтобы при нажатии кнопки соответствующее значение отрицалось
class Parent extends React.Component{
constructor(props){
super(props);
this.state={
a: true,
b: false,
c: true,
d: false
}
this.handleAction = this.handleAction.bind(this);
}
handleAction(action) {
this.setState({
name: !this.state.name
});
}
render(){
return(
<div>
<Child onAction={this.handleAction} name='a'/>
<Child onAction={this.handleAction} name='b'/>
<Child onAction={this.handleAction} name='c'/>
<Child onAction={this.handleAction} name='d'/>
</div>
)
}
}
function Child({onAction, name}){
return (
<button onClick={onAction}>
{name}
</button>
);
}
есть ли способ сделать это без 4 отдельных функций handleAction? я попытался передать name
в onAction
, но это выдает Error: Maximum update depth exceeded
я знаю, что должно быть что-то действительно очевидное, чего мне не хватает, спасибо за вашу помощь.
Ответ №1:
Вы могли бы передать name
в качестве параметра вашей handleAction
функции
....
handleAction(name) {
this.setState( state => ({ [name]: !state[name] }) );
}
render(){
return(
<div>
<Child onAction={() => this.handleAction('a')} name='a'/>
<Child onAction={() => this.handleAction('b')} name='b'/>
<Child onAction={() => this.handleAction('c')} name='c'/>
<Child onAction={() => this.handleAction('d')} name='d'/>
</div>
)
}
...
Обратите внимание, что чтение this.state
изнутри this.setState
не является хорошей практикой. смотрите здесь
Комментарии:
1. это работает, спасибо, не могли бы вы, пожалуйста, объяснить причину возврата другой функции, как вы делали раньше
handleAction
, и другие делали внутри нее вместо прямого изменения состояния, как я сделал?2. Конечно! причина, по которой не используется
this.state
непосредственно внутриsetState
, заключается в том, чтоsetState
является асинхронным по своей природе, что означает, чтоsetState
это не применяется немедленно. Хотя здесь это маловероятно, существует риск того, что приsetState
повторном вызове оба они могут найти одно и то же значение вthis.state
, посколькуsetState
, возможно, оно еще не было применено. Обновление стиля функцииthis.setState(state => ...)
останавливает чтение устаревших значений изthis.state
. Вы можете найти подробный пример в документах react3. извините, возможно, я не совсем ясно выразился, я имел в виду добавленный on
()=>
в вашемonAction={() => this.handleAction('a')}
Ответ №2:
Измените обработчик так, чтобы он мог принимать name и возвращать другую функцию.
handleAction(name) {
return () => {
this.setState({
[name]: !this.state[name],
});
};
}
В дочернем компоненте передайте имя этого дочернего компонента
<Child onAction={this.handleAction("a")} name='a'/>
Комментарии:
1. В
this.state
react docssetState
настоятельно не рекомендуется обращаться внутрь
Ответ №3:
Попробуйте это:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
a: true,
b: false,
c: true,
d: false,
};
this.handleAction = this.handleAction.bind(this);
}
handleAction(name) {
return () => {
console.log("name", name);
this.setState({
[name]: !this.state[name],
});
};
}
render() {
console.log("this.state", this.state);
return (
<div>
<Child onAction={this.handleAction} name="a" />
<Child onAction={this.handleAction} name="b" />
<Child onAction={this.handleAction} name="c" />
<Child onAction={this.handleAction} name="d" />
</div>
);
}
}
function Child({ onAction, name }) {
return <button onClick={onAction(name)}>{name}</button>;
}
Ответ №4:
Как я вижу, вы хотите использовать название кнопки, а затем изменить состояние с тем же именем. Во-первых, вы должны предоставить функции название кнопки. Поскольку событие передается функции по умолчанию, вы можете получить имя, например, таким образом:
event.target.innerText
Затем, если вы используете name в качестве переменной, содержащей значение, вы должны использовать обозначение [name]. В противном случае это добавит свойство ‘name’ к вашему объекту.
В результате ваш обработчик должен выглядеть следующим образом:
handleAction(e) {
const name = e.target.innerText
this.setState({
[name]: !this.state[name]
});
}