javascript - React的状态更新问题,请老司机看一眼,多谢!
黄舟
黄舟 2017-04-11 09:44:54
[JavaScript讨论组]

我初学react写了一个小组件,在更新组件状态的时候发现计算数据有些不正确。请教一下。
▼如下图:

目的是每增加一个苹果,苹果数量增加一个,同时更新总重&总计金额。
目前问题是,从0增加到1个苹果时,合计金额没有变化。请帮看一下哪里的问题。谢谢老司机。
good man one life safe.
▼部分相关代码如下

<body>
<p id="p01">
    插件未正确加载
</p>
<script type="text/babel">
    var BuyApple = React.createClass({
        render: function () {
            return (
                    <p >
                        <p>
                            购买<span>{this.state.shuLiang}</span>个苹果,
                            每个<span>{this.state.danZhong}</span>斤,
                            每斤<span>{this.state.danJia}</span>元,
                            一共<span>{this.state.zongZhong}</span>斤,
                            合计<span>{this.state.zongJi}</span>元。
                        </p>
                        <input type="button" value="增加苹果" onClick={ this.addApple}/>
                        <input type="button" value="减少苹果" onClick={ this.reduceApple}/>
                        <input type="button" value="增加单价" onClick={ this.addMoney}/>
                        <input type="button" value="减少单价" onClick={ this.reduceMoney}/>
                    </p>
            );
        },
        getInitialState:function () {
            return{
                shuLiang: 0, //数量
                danZhong: 0.5, //单重
                danJia:2, //单价
                zongZhong: 0, //总重
                zongJi: 0, //总计
            }
        },
        addApple:function () {
            this.setState({ //▼问题八成出在这里
                shuLiang: ++this.state.shuLiang, //苹果数量加1
                zongZhong: this.state.shuLiang * this.state.danZhong, //苹果总重=数量*单重
                zongJi: this.state.zongZhong * this.state.danJia, //总计=总重*单价
            });
        },
    });
    ReactDOM.render(
        <BuyApple/>,
        document.querySelector('#p01'),
    );
</script>
</body>
黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回复(9)
伊谢尔伦

最主要的原因是setState是个异步的操作

this.setState({ 
           shuLiang: ++this.state.shuLiang, //苹果数量加1
           //问题出在设置zongZhong的时候拿到的shuLiang是旧的
           zongZhong: this.state.shuLiang * this.state.danZhong, //苹果总重=数量*单重
           zongJi: this.state.zongZhong * this.state.danJia, //总计=总重*单价
            });

两个方案

  1. 按照楼上说的,总重在render里去算

  2. setState有第二个参数,是个callback,可以拿到新的state,你可以在这个callback里去设置总重,甩一个文档

当然,我建议你用第一种方案

伊谢尔伦

你在同一个setState里设置数量和总重,实际上总重调用的this.state.shuLiang还没改变,还是之前的值。压根就不用保存太多的state。

<p>
    购买<span>{this.state.shuLiang}</span>个苹果,
    每个<span>{this.state.danZhong}</span>斤,
    每斤<span>{this.state.danJia}</span>元,
    一共<span>{this.state.shuLiang * this.state.danZhong}</span>斤,
    合计<span>{this.state.shuLiang * this.state.danZhong * this.state.danJia}</span>元。
</p>
PHPz

state里面要存最少的值,能通过计算出来的都不能存

黄舟

这个zongJi不要放在state里面,在展示的时候直接算出来就行了。

巴扎黑

1:state要使用最小状态集合

 return{
                shuLiang: 0, //数量
                danZhong: 0.5, //单重
                danJia:2, //单价
                zongZhong: 0, //总重
                zongJi: 0, //总计
            }

明显,zongZhong和zongJi是可以通过前面三个state计算出来的。

2:建议在render里计算,不要在setState里是算。

3:问题的根本原因是@zhangfe的解释,为了性能优化,React的setState(new State, callback)是异步的,他甩的文档里说得很清楚。

迷茫

没用过react,但是我猜测问题大概是这样的。我认为setState方法大概是这样的

this.setState = function(obj) {
    for(var key in obj) {
        this.state[key] = obj[key];
    }
    ...
}

而你的代码运行过程实际上是

var obj = {
    shuLiang: ++this.state.shuLiang, //苹果数量加1
    zongZhong: this.state.shuLiang * this.state.danZhong, //苹果总重=数量*单重
    zongJi: this.state.zongZhong * this.state.danJia, //总计=总重*单价
}

然后再
this.setState(obj);
这时候obj里面的值已经计算完了,所以导致的结果不正确。
所以你可以

var obj = {};
obj.shuLiang = this.state.shuLiang + 1;
obj.zongZhong = obj.shuLiang * this.state.danZhong;
obj.zongJi = obj.zongZhong * this.state.danJia;
this.setState(obj);
伊谢尔伦

....多看下文档,很多api后面都不止我们常用的一个参数,还有能不能用英文,拼音看着挺别扭的。养成个好习惯嘛,大家共勉。

高洛峰

其实吧,使用定时器是个很好的选择,在didMount的时候调用计时器,在willMount的时候清空计时器

ringa_lee

按照官方文档,state应该保存尽量少的变量,其它可以算出来的再在render函数中更新

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号