React-组件-setState

setState 是如何给 state 赋值的

  • 通过 Object.assign()
import React from 'react';

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: 'BNTang',
            age: 18
        }
        let oldObj = {name: 'BNTang', age: 18};
        let newObj = {age: 666};

        let obj = Object.assign({}, oldObj, newObj);
        console.log(obj);
    }

    render() {
        return (
            <div>
                <p>{this.state.name}</p>
                <p>{this.state.age}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>按钮
                </button>
            </div>
        )
    }

    btnClick() {
        this.setState({
            age: 666
        });
    }
}

class App extends React.Component {
    render() {
        return (
            <div>
                <Home/>
            </div>
        )
    }
}

export default App;

image-20220417232753576

state 合并现象

  • 因为 setState 会收集一段时间内所有的修改操作,然后在统一的执行,再更新界面
  • 所以就出现了 state 的合并现象

首先来看一个案例,然后引出这个 state 的合并场景先如下:

import React from 'react';

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            age: 0
        }
    }

    render() {
        return (
            <div>
                <p>{this.state.age}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>按钮
                </button>
            </div>
        )
    }

    btnClick() {
        this.setState({
            age: this.state.age + 1
        });
        this.setState({
            age: this.state.age + 1
        });
        this.setState({
            age: this.state.age + 1
        });

        console.log(this.state.age);
    }
}

class App extends React.Component {
    render() {
        return (
            <div>
                <Home/>
            </div>
        )
    }
}

export default App;

然后查看结果发现居然是 1:

image-20220417233223604

为什么最终的一个值是1, 不是 3 呢是吧,我明明是进行增加了 3 次加 1 的操作,因为 setState 默认是一个异步的方法, 默认会收集一段时间内所有的更新, 然后再统一更新, 所以就导致了最终的一个值是 1, 不是 3,博主可以大致的提供一下它底层的实现代码这样可以更加的让你对 setState 有更深层次的理解,如下:

let oldObj = {age: 0};
let stateList = [
    // 演变过程1
    // {age: oldObj.age + 1},
    // {age: oldObj.age + 1},
    // {age: oldObj.age + 1},

    // 演变过程2
    // {age: 0 + 1},
    // {age: 0 + 1},
    // {age: 0 + 1},

    // 演变过程3
    {age: 1},
    {age: 1},
    {age: 1}
];
stateList.forEach((newObj) => {
    // 演变过程1
    // Object.assign({}, {age: 0}, {age: 1}); // {age: 1}

    // 演变过程2
    // Object.assign({}, {age: 1}, {age: 1}); // {age: 1}

    // 演变过程3
    // Object.assign({}, {age: 1}, {age: 1}); // {age: 1}
    oldObj = Object.assign({}, oldObj, newObj);
});

console.log(oldObj);

解决 state 合并现象

第一种方案就是前面所说的通过 setState 方法的第二个参数, 通过回调函数拿到更新之后的值,然后在根据该值在进行加一操作如下:

import React from 'react';

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            age: 0
        }
    }

    render() {
        return (
            <div>
                <p>{this.state.age}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>按钮
                </button>
            </div>
        )
    }

    btnClick() {
        this.setState({
            age: this.state.age + 1
        }, () => {
            this.setState({
                age: this.state.age + 1
            }, () => {
                this.setState({
                    age: this.state.age + 1
                });
            });
        });
        console.log(this.state.age);
    }
}

class App extends React.Component {
    render() {
        return (
            <div>
                <Home/>
            </div>
        )
    }
}

export default App;

但是上面的代码存在弊端,层级结构比较深,以后维护比较不友好,所以说 React 也考虑到了这一点,所以这里就引出了第二种解决方案,通过 setState 的第一个参数来进行解决,第一个参数除了可以传递一个对象,其实还可以传递一个回调函数,回调函数有两个默认的参数第一个就是上一次更新的最新的值,然后我们可以在该回调函数中就可以直接拿到最新的值,就不会出现合并的现象了。

import React from 'react';

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            age: 0
        }
    }

    render() {
        return (
            <div>
                <p>{this.state.age}</p>
                <button onClick={() => {
                    this.btnClick()
                }}>按钮
                </button>
            </div>
        )
    }

    btnClick() {
        this.setState((preState, props) => {
            return {age: preState.age + 1};
        });
        this.setState((preState, props) => {
            return {age: preState.age + 1};
        });
        this.setState((preState, props) => {
            return {age: preState.age + 1};
        });
        console.log(this.state.age);
    }
}

class App extends React.Component {
    render() {
        return (
            <div>
                <Home/>
            </div>
        )
    }
}

export default App;

image-20220417234700880

那么为什么这样就可以解决从 0 变为 3 呢,这里也提供出它底层的实现,和演变过程,可以更深层次的加深理解:

let oldObj = {age: 0};

let stateList = [
    (preState) => {
        return {age: preState.age + 1}
    },
    (preState) => {
        return {age: preState.age + 1}
    },
    (preState) => {
        return {age: preState.age + 1}
    },
];

stateList.forEach((fn) => {
    // 演变过程1
    // {age: 1}

    // 演变过程2
    // {agg: 2}

    // 演变过程3
    // {agg: 3}

    let newObj = fn(oldObj);

    // 演变过程1
    // {age: 0} {age: 1} / {age: 1}

    // 演变过程2
    // {age: 1} {age: 2} / {age: 2}

    // 演变过程3
    // {age: 2} {age: 3} / {age: 3}
    oldObj = Object.assign({}, oldObj, newObj);
});
console.log(oldObj);
posted @ 2022-04-17 23:49  BNTang  阅读(45)  评论(0编辑  收藏  举报