我不知道这是已知问题还是预期功能,但我发现了一个有趣的问题。
所以我们都知道,如果要在React中呈现反应式值,我们必须将值放入状态并使用setState:
constructor() {
super();
this.state = { counter: 0 }
this.incrementButtonListener = (e) => {
e.preventDefault();
this.setState(prevState => ({ counter: prevState.counter + 1 }));
};
}
render() {
return (
<div>
<h1>{this.state.counter}</h1>
// When clicked, counter increments by 1 and re-renders
<button onChange={this.incrementButtonListener}>Increment</button>
</div>
)
}
但是,如果我们将counter
作为字段属性,则render()仅在创建组件时才捕获counter
的快照,甚至在counter
递增时,结果将不会在render()中反应性地显示:
constructor() {
super();
this.counter = 0;
this.incrementButtonListener = (e) => {
e.preventDefault();
this.counter++;
};
}
render() {
return (
<div>
<h1>{this.counter}</h1>
// When clicked, counter increments by 1 but the difference is NOT rendered
<button onChange={this.incrementButtonListener}>Increment</button>
</div>
)
}
对吗?基本的东西。
但是,当我尝试弄乱这段代码时,会发生一种有趣的情况。我们将字段属性作为其他属性保持不变。唯一的区别是,在incrementButtonListener
中,我要在setState
上添加一个someStateProperty
:
constructor() {
super();
this.counter = 0;
this.incrementButtonListener = (e) => {
e.preventDefault();
this.counter++;
/*-------------------------------ADD THIS*/
this.setState({});
// You have to pass an object, even if it's empty. this.setState() won't work.
/*-----------------------------------------*/
};
}
render() {
return (
<div>
<h1>{this.counter}</h1>
// Surprise surprise, now this.counter will update as if it was in the state!
<button onChange={this.incrementButtonListener}>Increment</button>
</div>
)
}
这次,this.counter就像状态一样更新!
所以我的假设是,每次调用setState时(甚至使用一个空对象作为参数),render()都会再次运行,this.counter
将得到重新计算,并因此而递增。当然,它不会像状态属性那样具有100%的反应性。但是,在这种使用情况下,this.counter
唯一会改变的时间是我单击Increment
按钮时。因此,如果我将setState放在侦听器中,它将像this.counter
一样工作。
现在,我不确定这是一种可以接受的行为,还是只是一个意外的黑客行为,以及我是否应该使用它。有人可以帮我详细说明吗?
如果要查看实际行为,请在此处fiddle。您可以注释掉第7行中的this.setState({})
位以查看区别。
答案 0 :(得分:1)
因为您没有截获状态变化,所以会导致重新渲染,进而导致使用增量实例属性。这是设计使然。对React状态的任何更改都将导致组件重新呈现,除非您使用生命周期挂钩来控制是否应该发生这种情况。
请参见https://reactjs.org/docs/react-component.html#shouldcomponentupdate
答案 1 :(得分:1)
请使用this.state
和setState
,因为它有自己的用途。
通过使用React状态机制,我们得到了诸如冗长,类似于函数的编程风格这样的好处,即函数应该是纯函数而不是对数据进行变异。
每次调用setState
时,它将使用新值来代替现有值,并使行为不可预测。
通过使用shouldComponentUpdate
检查组件内部的道具/状态,您还可以防止组件重新渲染或更新。
在您的应用变得越来越复杂之后,诸如Redux
之类的库可能会在将来为您省钱。对于更简单的组件或应用,React状态就足够了。
进一步阅读:
https://reactjs.org/docs/faq-state.html
https://reactjs.org/docs/state-and-lifecycle.html
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
https://spin.atomicobject.com/2017/06/07/react-state-vs-redux-state/
答案 2 :(得分:1)
您可以在forcrUpdate上替换setState。 如果您的团队使用装饰风格的代码,则切勿使用setState({})或forceUpdate()。 React的作者建议使组件像纯函数一样。
答案 3 :(得分:0)
class Hello extends React.Component {
state = { counter: 0 };
increment = () => {
const { counter } = this.state;
this.setState({ counter: counter + 1 });
};
decrement = () => {
const { counter } = this.state;
this.setState({ counter: counter - 1 });
};
render() {
const { counter } = this.state;
return (
<div>
<h1>{counter}</h1>
<p>
<button onClick={this.increment}>Increment</button>
</p>
<p>
<button onClick={this.decrement}>Decrement</button>
</p>
</div>
);
}
}
ReactDOM.render(<Hello />, document.getElementById("container"));
我希望这可以帮助您做出反应!让我知道您是否有任何问题:)