组件中 setState() 如何细粒度操作?

2016-03-11 17:16:17 +08:00
 iugo

使用 React Native 0.21.

如何细粒度修改数据, 比如只增加数据到 state.input 中.

理想解决方法:

this.setState({name: 'Jim'}, 'input')
this.setState({Age: '24'}, 'input')
// state = {input: {name: 'Jim', Age: '24'}}

目前解决方法:

(userName) => this.setState(
function (previousState) {
return {input: Object.assign({}, previousState.input, {userName: userName})}
}
)

或许我这样想压根儿就是不对的, 当存在多层级的时候, 就应该进行组件拆分. 每个组件都是扁平的. 如果想树形结构, 那就干脆 Redux 吧.

Redux 多组件中如何 connect() 还是有点懵. 所以暂时没有使用 Redux.

3032 次点击
所在节点    React
10 条回复
lizheming
2016-03-11 17:32:44 +08:00
this.state.input.Age = 24;
this.forceUpdate();
iugo
2016-03-11 17:34:27 +08:00
@lizheming 官方不建议直接修改 state 呀.
leojoy710
2016-03-11 17:36:41 +08:00
替换整个 state 也没什么问题吧...redux 就是这么干的...
lizheming
2016-03-11 17:52:54 +08:00
@iugo 不建议的原因是因为 setState 会自动帮我们 render ,所以你在确定需要 render 的时候加上 forceUpdate 就好啦。
iugo
2016-03-11 18:15:29 +08:00
@leojoy710
@lizheming

我怕自己强制渲染可能造成不必要的开销.

这是一种解决办法. 谢谢.
lizheming
2016-03-11 18:20:31 +08:00
@iugo 你自己强制渲染也是调用 React 的方法啊,为啥会有开销,而且在你有时候需要多次 this.setState 的时候(当然这种情况极少)的时候可以统一赋值完之后再 forceUpdate 更节省呢。
iugo
2016-03-12 10:04:52 +08:00
@lizheming 比如在多组件中, 如果使用 forceUpdate 是否会导致所有组件都被重新渲染而不是只渲染涉及 state 变更的组件. 一个列表, 当有新的项目增加, append 新的项目而不是重新渲染整个列表.

React 应该是根据数据的变化, 有选择地进行渲染, 这样避免额外消耗吧.
lizheming
2016-03-12 11:00:12 +08:00
@iugo 不仅仅是根据数据渲染的哦,有很多变化是不依赖 state 数据存在的,比如我这个示例中很明显的 http://codepen.io/anon/pen/vGKwQE 时间,如果按照你的理解的话,子组件不被渲染时间肯定是不变的,然而事实不是这样的。

forceUpdate 只是说当你没有更新的时候也会产生 render 而已,下面的代码可以很好的证明:
https://github.com/facebook/react/blob/10f9476f3adc6658067afbf2e27c4826649f8255/src/renderers/shared/reconciler/ReactCompositeComponent.js#L646-L654

所以说其实在当你确认需要 render 的时候(你已经更改了 state 有明确的 render 需求) forceUpdate 和 setState 干的事情是一样的,不必要对性能太过担心啦。不过有一点需要注意的是,因为 forceUpdate 会强制更新,跳过 componentShouldUpdate 这个生命周期的判断,所以如果有这方面的操作的话需要确认一下。
keyanzhang
2016-06-06 15:17:26 +08:00
@lizheming 不建议您这样手动 mutate this.state 然后使用 forceUpdate 。这其实是一个 anti-pattern : this.state 这个 object 本身不会发生变化( oldState === newState ),而且像您说的一样这会跳过 shouldComponentUpdate 。换句话说就是您没有办法对是否需要 render 这件事做清晰的逻辑判断了。另外一个例子是如果 https://github.com/facebook/react/pull/6914 可以被 merge , forceUpdate 也会造成一些 heuristic 上的问题。具体您可以看 https://github.com/facebook/react/pull/6914/files#diff-748cbc3aec3f23e1ba85ea1706063ccfR178
lizheming
2016-06-06 15:45:32 +08:00
@keyanzhang 不好意思,那个 pull 英文太多我没看懂。。。
this.state 使用 setState 创建是 immutable 的,这个没错,如果你介意引用的问题的话那还是别直接改吧,事实上 setState 应该也是因为内部是浅拷贝的原因,所以才没办法做楼主那样的深度赋值。
另外跳过 shouldComponentUpdate 这个周期其实影响不大,因为我已经确认我的数据需要更新到视图上,那么在 this.forceUpdate() 那一刻我是非常明确需要重新 render 这个事实的,所以不存在您中间说的“无法判断是否需要 render ”。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/262832

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX