简体   繁体   English

React.map 不重新渲染

[英]React .map not re-rendering

I'm building a sorting algorithm visualizer, and in my return, I'm creating divs to represent vertical bars, in animatedBubbleSort() I'm swapping values in the state array on a timeout, the array IS being sorted, but what I expected to happen was that the.map function would be re-rendered each time the state is changed with updateArray().我正在构建一个排序算法可视化工具,作为回报,我正在创建 div 来表示垂直条,在 animatedBubbleSort() 中,我在超时时交换 state 数组中的值,数组正在排序,但我预计会发生的是,每次 state 被 updateArray() 改变时,.map function 都会被重新渲染。 But the.map function does not re-fire at all.但是 .map function 根本不会重新触发。

import React, { useState } from "react";
import "../styles/App.css";
import { Header } from "./Header";

export default function SortingVisualizer(props) {
    const LOWER_BOUND = 5;
    const UPPER_BOUND = 200;
    const ARRAY_SIZE = 200;

const [array, updateArray] = useState(fillArrayWithRandomValues);

// returns a random number between bounds inclusive
function randomNumberBetweenBounds() {
    return Math.floor(Math.random() * UPPER_BOUND) + LOWER_BOUND;
}

// fills array with random values
function fillArrayWithRandomValues() {
    let tempArray = [];
    for (let i = 0; i < ARRAY_SIZE; i++) {
        tempArray.push(randomNumberBetweenBounds());
    }
    return tempArray;
}

function animatedBubbleSort() {
    let tempArr = array;
    let len = tempArr.length;
    for (let i = 0; i < len; i++) {
        for (let j = 0; j < len; j++) {
            if (tempArr[j] > tempArr[j + 1]) {
                let tmp = tempArr[j];
                tempArr[j] = tempArr[j + 1];
                tempArr[j + 1] = tmp;
                setTimeout(() => {
                    updateArray(tempArr);
                }, 300 * i);
            }
        }
    }
}

return (
    <div>
        <Header bubbleSort={animatedBubbleSort} />
        <div className="array-container">
            {array.map((value, idx) => {
                return (
                    <div
                        style={{ height: `${value * 2}px` }}
                        className="array-bar"
                        key={idx}
                    ></div>
                );
            })}
        </div>
    </div>
);

} }

It's because you're using the index of the elements in the array as the key.这是因为您使用数组中元素的索引作为键。 React uses key to decide which elements to rerender; React 使用key来决定重新渲染哪些元素; because your keys are always in the same order, React won't update anything.因为你的键总是按相同的顺序,React 不会更新任何东西。 Try:尝试:

{array.map((value) => {
    return (
        <div
            style={{ height: `${value * 2}px` }}
            className="array-bar"
            key={value}
        ></div>
    );
})}

See https://reactjs.org/docs/lists-and-keys.html#keys for more, specifically the following:有关更多信息,请参阅https://reactjs.org/docs/lists-and-keys.html#keys ,具体如下:

We don't recommend using indexes for keys if the order of items may change.如果项目的顺序可能发生变化,我们不建议对键使用索引。 This can negatively impact performance and may cause issues with component state.这会对性能产生负面影响,并可能导致组件状态出现问题。 Check out Robin Pokorny's article for an in-depth explanation on the negative impacts of using an index as a key .查看 Robin Pokorny 的文章, 深入了解使用索引作为键的负面影响 If you choose not to assign an explicit key to list items then React will default to using indexes as keys.如果您选择不为列表项分配显式键,那么 React 将默认使用索引作为键。

The other answers are correct, too.其他答案也是正确的。

Try using a unique value in the key, but the main problem is that TempArray = array assigns both variables to the same reference.尝试在键中使用唯一值,但主要问题是TempArray = array将两个变量分配给同一个引用。 Because of this, when React tries to compare array with tempArray they would be the same value, and this won't trigger a re-render.正因为如此,当 React 尝试将arraytempArray进行比较时,它们将是相同的值,并且这不会触发重新渲染。

To effectively make a copy of an array, try tempArray = [...array] to avoid making unwanted changes in the original array.要有效地复制数组,请尝试tempArray = [...array]以避免在原始数组中进行不必要的更改。

TLDR: Try updateArray(tempArr.slice(0)) TLDR:试试 updateArray(tempArr.slice(0))

I struggled with the same problem for quiet some time and the answers did not solve my problem.我在同样的问题上挣扎了一段时间,但答案并没有解决我的问题。

If you use modifiedState.slice(0) a duplicate of the prepended object is created, then use setState(modifiedState.slice(0)) or in your case updateArray(tempArr.slice(0)).如果您使用 modifiedState.slice(0),则会创建前缀 object 的副本,然后使用 setState(modifiedState.slice(0)) 或在您的情况下使用 updateArray(tempArr.slice(0))。 This forces.map-Operation to rerender.这 forces.map-Operation 重新渲染。

For anyone who comes across this and is already using an ID as their key, my issue was I was doing a double map, but rendering the second array.对于遇到此问题并且已经使用 ID 作为其密钥的任何人,我的问题是我正在执行双 map,但渲染第二个数组。 I had to change my key from the parent map id, to the rendered map id so React could detect a change.我必须将我的密钥从父 map id 更改为呈现的 map id,以便 React 可以检测到更改。

results.map((product) => {
                  return product.variants.map((variant) => (
                    <div
                      key={variant.id} <-- changed from product.id to variant.id
                    >
                      <div>
                        {product.title} - {variant.title}
                      </div>
                      <div className='font-weight-light'>{variant.sku}</div>
                    </div>
                  ));
                })

This won't work in every situation but I managed to fix my similar issue by using a random number as the index.这并非在所有情况下都有效,但我设法通过使用随机数作为索引来解决我的类似问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM