• React中使用useState()导致的问题记录


    https://www.jianshu.com/p/d9158074176b

    场景一: 更新 state 的一个对象(或数组)属性的某个子属性或值。

    使用 Hook Function Component

    function App() {
        const [arr, updateArr] = useState([]);
        const addList = () => {
            arr.push('Hello React');
            updateArr(arr);
        };
        return (
            <div>
                {
                    arr.map((item, index) => (
                        <p key={index}>{index} {item}</p>
                    ))
                }
                <button onClick={addList}>添加List</button>
            </div> 
        );
    }
    

    使用 Class Component

    class App extends Component {
        constructor(props) {
            super(props);
            this.state = {
                arr: []
            }
        }
    
        addList = () => {
            let arr = this.state.arr;
            arr.push('Hello React');
            this.setState({
                arr: arr
            }, () => {
                console.log(this.state.arr);
            });
        };
    
        deleteList = () => {
            const { arr } = this.state;
            arr.splice(0, 1);
            this.setState({
                arr: arr
            }, () => {
                console.log(this.state.arr);
            });
        };
    
        render() {
            const { arr } = this.state;
            return (
                <div>
                    {
                        arr.map((item, index) => (
                            <p key={index}>{index} {item}</p>
                        ))
                    }
                <button onClick={this.addList}>添加List</button>
                <button onClick={this.deleteList}>删除List</button>
            </div> 
            );
        }
    }
    

    结果:使用 Hook Function Component push 数组后数组长度并没有改变,使用Class Component正常。
    原因:在 Hook 中直接修改 state 的一个对象(或数组)属性的某个子属性或值,然后直接进行 set,不会触发重新渲染。

    • 对 Class Component来说,state 是 Immutable 的,setState 后一定会生成一个全新的 state 引用。它是通过 this.state 方式读取 state,所以每次代码执行都会拿到最新的 state 引用。
    • 对 Hook Function Component 而言,useState 产生的数据也是 Immutable 的,通过数组第二个参数 Set 一个新值后,原来的值会形成一个新的引用在下次渲染时。

    解决方案

    改变引用地址

    function App() {
        const [arr, updateArr] = useState([]);
        const addList = () => {
            arr.push('Hello React');
            // 通过扩展运算符实现深拷贝
            updateArr([...arr]);
        };
        return (
            <div>
                {
                    arr.map((item, index) => (
                        <p key={index}>{index} {item}</p>
                    ))
                }
                <button onClick={addList}>添加List</button>
            </div> 
        );
    }
    

    场景二: 在setTimeout中更改state。

    使用 Hook Function Component

    function App() {
        const [count, updateCount] = useState(0);
    
        useEffect(() => {
            let timer = setTimeout(() => {
                updateCount(1);
                getCount();
            }, 1000);
            return () => {
                clearTimeout(timer);
            }
        }, []);
    
        const getCount = () => {
            console.log(count); // result: 0
        };
        
        return (
            <div>{count}</div> 
        );
    }
    

    使用 Class Component

    let timer = null;
    export default class App extends Component {
        constructor(props) {
            super(props);
            this.state = {
                count: 0
            }
        }
    
       componentDidMount() {
            timer = setTimeout(() => {
                this.setState({
                    count: 1
                })
                this.getCount();
            }, 1000);
       }
    
    
       getCount = () => {
            console.log(this.state.count); // result: 1
       }
    
       componentWillUnmount() {
            clearTimeout(timer);
       }
    
        render() {
            const { count } = this.state;
            console.log(count); // result: 1
            return (
                <div>{count}</div> 
            );
        }
    }
    

    结果:使用 Hook Function Component 更改count后,页面显示1,getCount方法中打印的count为0,使用Class Component更改count后页面显示1,getCount方法中打印的count为1。
    原因:Hook Function Comoponent中由于对 state 的读取没有通过 this. 的方式,使得每次 setTimeout 都读取了当时渲染闭包环境的数据,虽然最新的值跟着最新的渲染变了,但旧的渲染里,状态依然是旧值。

    解决方案

    使用ref

    function App() {
        const [count, updateCount] = useState(0);
    
        useEffect(() => {
            let timer = setTimeout(() => {
                updateCount(1);
                getCount();
            }, 1000);
            return () => {
                clearTimeout(timer);
            }
        }, []);
    
        let ref = useRef();
        ref.current = count;
        const getCount = () => {
            console.log(ref.current); // result: 1
        };
        
        return (
            <div>{count}</div> 
        );
    }
    

    The End~

    附上我认为比较值得研读的相关文章:

    1.react-hook-usestate-setState
    2.精读《Function Component 入门》

  • 相关阅读:
    leetcode & lintcode 题解
    部署 Flask 应用时,为什么会需要 gunicorn 或 uWSGI?
    ubuntu vim python配置
    深度学习Momentum(动量方法)
    spark shuffle原理
    c++多态特性总结
    FM/FFM原理
    hadoop streaming怎么设置key
    归一化的优点和方法
    九章算法强化
  • 原文地址:https://www.cnblogs.com/plBlog/p/13993778.html
Copyright © 2020-2023  润新知