关于React属性传递和状态合并的问题。

发布于 2022-09-12 02:14:08 字数 1103 浏览 9 评论 0

大佬们,不吝赐教,手动抱拳了。内容有点长……

有一个形如这样的state:
state={
属性:{...obj}或者是一个对象组数
}

react组件传递参数是复制该对象还是直接传引用?

①就比如父组件state里有一个对象(也就是上面的属性),然后把这个对象用props的方式传给子组件,然后子组件对这个参数的某个属性做了修改,会不会导致父组件的状态变了(或者是react根本意识不到state里的某个属性的内容发生了变化?),而导致渲染?还是说推荐不修改属性只是访问它而避免该问题?
就像antd中的input,这个input应该是受控组件,它的值存在form里,传给input,修改input属性,导致form状态值发生变化,而后触发渲染,让input的值发生变化,当然这个过程是我猜的,新手玩家看不懂人家的源码。

我猜应该是传递的引用,复制该对象传给子组件不现实,该从哪些地方学习一下react关于这方面的知识。

②还有一个问题:当setState或者是return返回一个state的属性去合并状态值时,是会替换原state对象的对应属性,还是会新开一个state对象把旧的属性和新的属性合并起来?我猜应该是新开state对象,这样react会很容易意识到状态发生了变化。合并的时候又有问题了:是直接把传的属性合并进去还是复制了一份传的属性。

③又出现个问题,如果是直接把传的属性合并进去了,当这个属性和原本状态值里的属性是同一个对象时(假设由父组件引用传值给子组件),react是如何判断状态值发生了变化的,因为此时属性引用的对象是没变化的,只是引用对象的属性发生了变化(或者是判断该属性本身的内存地址和原来的state该属性的内存地址是否发生变化,如果变化了,说明这个属性肯定是新合并进来的,至于值变没变就不考虑了,直接渲染使用该属性的页面元素)。如果是新开一个state对象,那么react可能认为全部的状态值都发生了变化而触发渲染。或者是react维护之前旧的state,和新的state作对比,如果state的某个属性的对象地址变了(也可能不变),就认为这个值发生了变化从而只是重新渲染对应该值的页面元素。而如果像前面说的,如果是state的对象地址并没有变化,那么react是如何判断要重新渲染的,还是说无脑渲染,不管变没变?

该从哪方面学习上面这一部分关于如何合并状态和判断状态发生了改变这一方面的知识?

抱拳了,大佬们。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

时光清浅 2022-09-19 02:14:08

我来尝试回答一下:

Q: 针对问题一,对象(或数组),作为state时,传递的应用,还是拷贝

A: 回答:是引用

Q: 改变对象(会数组)的值时,是如何触发组件更新的

A: 回答:因为传的是引用,新旧state比较时,是浅比较,所以更改对象(或数组)的值时,不能触发更新(即使有其它原因触发了更新,也会更新不及时),也即是不存在“合并”的问题

写一下代码,就知道答案了,举个栗子:


import React, { useState } from 'react';

function App() {

    const [obj1, setObj1] = useState({ a: 1 });
    const [obj2, setObj2] = useState({ a: 2 });

    // 猜猜看obj1会不会实时更新,obj2呢
    return (
        <div className="App">
            <button onClick={() => {
                ++obj1.a; setObj1(obj1)
            }}>点我暴力+1</button>
            <div>{JSON.stringify(obj1)}</div>
            <button onClick={() => {
                let newObj2 = Object.assign({}, obj2);
                ++newObj2.a;
                setObj2(newObj2);
            }}>
                我创建一个新对象 + 1
            </button>
            <div>{JSON.stringify(obj2)}</div>
        </div>
    );
}

export default App;

那么如何触发对象更新呢,在旧的API中,可以通过shouldComponentUpdate中,比较,比如

shouldComponentUpdate(nextProps, nextState) {
    if (JSON.stringfy(this.state.obj) !== JSON.stringfy(nextState.obj)) {
        return true;
    }
}

当然也可以像栗子中直接new一个新对象,强制改变引用,来触发更新,比如

const {obj} = this.state;
let newObj = Object.assign({}, obj);
// array 就 let newArray = [...array]
newObj.a = 1;
this.setState({
    obj: newObj
})

当然,还可以调用React中的forceUpdate强制触发更新;
当然,也可以用一些Immutable的对象(或许这个才是题主想知道的合并吧),来进行性能优化;

不要将React的diff算法和state的比较弄混哦。

——————————————————————

如有错谬,请指出,一起进步~

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文