useCallback и React.memo доступ к состоянию

#javascript #reactjs #callback #frontend #memoization

#javascript #reactjs #обратный вызов #интерфейс #запоминание

Вопрос:

У меня есть плата функциональных компонентов, и в возвращаемом JSX я просматриваю 2D-массив и печатаю кучу квадратов, и я передаю обработчик плюс некоторую дополнительную информацию в каждый из них. Я хотел предотвратить их повторный рендеринг, если Квадрат получает те же реквизиты, поэтому компонент Square находится в методе React.memo(). В компоненте платы, где я обрабатываю обновления платы, у меня есть обработчик с useCallback, поэтому я не передаю совершенно новую функцию при повторных отправках.

Чего я не понимаю, так это того, что в теле clickHandler у меня всегда есть доступ к свежему обновленному 2D-массиву, вызываемому на board, но я никогда не получаю измененного игрока, он всегда остается равным 1. Тем не менее, само состояние переключается на 2 и наоборот. Если я передам player в качестве зависимости, все мои 300 квадратов будут перенаправлены повторно.

Я не передаю состояние в качестве опоры квадрату, я просто сопоставляю плату и передаю значения с самой платы.

Итак, мой вопрос в том, почему у меня есть доступ к обновленной плате в clickHandler, но не к проигрывателю. Например, когда я нажимаю на один из своих квадратов, он всегда принимается игроком1, который используется по умолчанию.

Ссылка на весь репозиторий (это всего лишь несколько компонентов): https://github.com/TreblaCodes/react-connect5

Спасибо

     const [player, setPlayer] = useContext(PlayerContext)
    const [board, setBoard] = useContext(PositionsContext)

    const clickHandler = useCallback((x,y) => {
        let board_copy = [...board]
        board_copy[y][x] = player;
        setBoard(board_copy) 
        console.log(board) //updated
        setPlayer(player === 1 ? 2 : 1)
        console.log(player) // stays at 1
    },[])
  

Ответ №1:

Просто попробуйте передать player и board во второй параметр useCallback . Затем всякий раз, когда игрок или доска будут изменены, вы получите новый экземпляр обратного вызова.

Вот так:

 const [player, setPlayer] = useContext(PlayerContext)
const [board, setBoard] = useContext(PositionsContext)

const clickHandler = useCallback((x,y) => {
    let board_copy = [...board]
    board_copy[y][x] = player;
    setBoard(board_copy) 
    console.log(board) //updated
    setPlayer(player === 1 ? 2 : 1)
    console.log(player) // stays at 1
},[player, board])
  

Комментарии:

1. Это затем заставляет все мои квадраты повторно отображать… Без каких-либо зависимостей плата в clickHandler является обновленной версией, но не игроком

2. Причина, по которой ваша плата обновляется, заключается в том, что вы нарушаете принцип неизменности. Эта строка «board_copy[y] [x] = player;» изменяет исходный объект.

3. пусть board_copy = […board], должен сделать копию

4. @Albert.Hadacek это не делает глубокую копию. Каждая запись ссылается на один и тот же объект. Итак, board_copy[y] === board[y]