V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iugo
V2EX  ›  React

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

  •  
  •   iugo ·
    iugo · 2016-03-11 17:16:17 +08:00 · 2869 次点击
    这是一个创建于 2965 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 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.

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

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

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

    React 应该是根据数据的变化, 有选择地进行渲染, 这样避免额外消耗吧.
    lizheming
        8
    lizheming  
       2016-03-12 11:00:12 +08:00   ❤️ 1
    @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
        9
    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
        10
    lizheming  
       2016-06-06 15:45:32 +08:00
    @keyanzhang 不好意思,那个 pull 英文太多我没看懂。。。
    this.state 使用 setState 创建是 immutable 的,这个没错,如果你介意引用的问题的话那还是别直接改吧,事实上 setState 应该也是因为内部是浅拷贝的原因,所以才没办法做楼主那样的深度赋值。
    另外跳过 shouldComponentUpdate 这个周期其实影响不大,因为我已经确认我的数据需要更新到视图上,那么在 this.forceUpdate() 那一刻我是非常明确需要重新 render 这个事实的,所以不存在您中间说的“无法判断是否需要 render ”。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5555 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 06:05 · PVG 14:05 · LAX 23:05 · JFK 02:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.