Как в React ререндерить только выбранные элементы массива

У меня есть довольно простая функциональная компонента, которая рендерит массив с числами от 0 до 14 и при нажатии на любое число меняет его с предыдущим местами по средставам смены индекса элемента. При каждом клике по элементу, у меня перерисовывается весь массив с числами т.е. console.log('test') вызывается 15 раз при каждом клике, как бы мне сделать так, чтобы ререндерились только те элементы, которые поменяли свое местоположение и console.log('test') вызывался только 2 раза?


function Test() {
  const [arr, setArr] = useState([]);
  useEffect(() => {
    const createNumbersForCell = () => {
      return [...Array(15).keys()];
    }
    setArr(createNumbersForCell());
  }, []);

  const replace = (item) => {
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] === item) {
        [arr[i], arr[i - 1]] = [arr[i - 1], arr[i]]
        setArr(prev => [...arr]);
      }
    }
  };

  return (
    <>
      {arr.map((item, index) => (
        <div key={index} onClick={() => {replace(item)}}>
          {item} {index} {console.log('test')}
        </div>
      ))}
    </>
  );
}

export default  Test ;

Ответы (2 шт):

Автор решения: Yuriy Sidorov

Попробуйте вместо ключа key={index} использовать уникальное значение которое не меняется, в вашем случае это например key={item}

→ Ссылка
Автор решения: frontedward

Может быть так попробовать:

function Test() {
  const [arr, setArr] = useState([]);
  useEffect(() => {
    const createNumbersForCell = () => {
      return [...Array(15).keys()];
    }
    setArr(createNumbersForCell());
  }, []);

  const replace = (item) => {
    const newArr = [...arr]; // создаем копию исходного массива
    for (let i = 0; i < newArr.length; i++) {
      if (newArr[i] === item) {
        [newArr[i], newArr[i - 1]] = [newArr[i - 1], newArr[i]];
        break; // прерываем цикл после обмена элементов
      }
    }
    setArr(newArr); // обновляем состояние только с измененными элементами
  };

  return (
    <>
      {arr.map((item) => (
        <div key={item} onClick={() => {replace(item)}}>
          {item} {console.log('test')}
        </div>
      ))}
    </>
  );
}

export default Test;
→ Ссылка