【问题标题】:React hook useState with array cause missing render calls使用数组反应钩子 useState 导致缺少渲染调用
【发布时间】:2020-02-16 07:55:48
【问题描述】:

我有以下代码:

function MyComponent( props ) {
    let arrSize = 5;
    const [arr, setArr] = useState( () => {
        let initial = new Array(arrSize);
        for(let i=0; i<arrSize; i++) initial.push({ foo: 'foo', bar: 'bar'});
        return initial;
    });

    mouseEventCallback = (e) => {
        // ...
        let tmp = arr;
        // ...
        setArr( tmp );
    }

    let cmp = [];
    for(let i=0; i<arrSize; i++) {  
       cmp.push( <span key={i} className={arr[i].foo}></span> );
    }

    return (
        <div>
           {cmp}
        </div>
    )
}

当鼠标回调调用几次时,我遇到了一个问题:状态参数更改正常(使用反应组件检查 Chrome 网络浏览器中的选项卡),但具有此状态的 DOM 元素并未全部重新渲染 - 其中一些具有旧状态。

当我添加虚拟状态时 - 一切正常:

function MyComponent( props ) {
    let arrSize = 5;
    const [arr, setArr] = useState( () => {
        let initial = new Array(arrSize);
        for(let i=0; i<arrSize; i++) initial.push({ foo: 'foo', bar: 'bar'});
        return initial;
    });
    const [dummy, setDummy] = useState(0);

    mouseEventCallback = (e) => {
        // ...
        let tmp = arr;
        // ...
        setArr( tmp );
        setDummy( Math.rand() );
    }

    let cmp = [];
    for(let i=0; i<arrSize; i++) {  
       cmp.push( <span key={i} className={arr[i].foo}></span> );
    }

    return (
        <div dataTest={dummy}>
           {cmp}
        </div>
    )
}

如何改进我的代码并以正确的方式解决我的问题?

【问题讨论】:

    标签: javascript reactjs mouseevent react-hooks react-functional-component


    【解决方案1】:

    您的组件不会在 setArr(tmp) 上重新渲染,因为“tmp”变量引用了与“arr”变量相同的数组。相同的引用意味着它们指向内存中的相同事物,因此当 react 在旧状态和新状态之间进行比较时,它们返回相同的事物,即 tmp === arr 返回 true。如果旧状态 = 新状态组件不会重新渲染。所以为了重新渲染;使“tmp”指向一个与“arr”具有相同数据的新数组。您可以使用 ES6 扩展运算符。

    更改:让 tmp = arr; 致:让 tmp = [...arr];

    let a = [1, 2, 3];
    let b = a;
    let c = [...a]; // ES6 Spread Operator
    
    a === b; // returns true
    a === c; // returns false

    正确代码:

    function MyComponent( props ) {
        let arrSize = 5;
        const [arr, setArr] = useState( () => {
            let initial = new Array(arrSize);
            for(let i=0; i<arrSize; i++) initial.push({ foo: 'foo', bar: 'bar'});
            return initial;
        });
    
        mouseEventCallback = (e) => {
            // ...
            let tmp = [...arr];
            // ...
            setArr( tmp );
        }
    
        let cmp = [];
        for(let i=0; i<arrSize; i++) {  
            cmp.push( <span key={i} className={arr[i].foo}></span> );
        }
    
        return (
            <div>
                {cmp}
            </div>
        )
    }
    

    【讨论】:

      猜你喜欢
      • 2020-08-03
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 2019-10-04
      • 2021-04-23
      • 1970-01-01
      • 1970-01-01
      • 2020-03-25
      相关资源
      最近更新 更多