useEffect не вызывается при изменении ref

При изменении переменной хука useRef, не вызывается useEffect

Переменные:

    const [hiddenLayers, setHiddenLayers] = useState([])
    
    const hiddenLayersRef = useRef([createHiddenLayerElement(1)])

Функции:

    function addLayer(key) {
        let hiddenLayersTemp = hiddenLayersRef.current
        let elementIndex = hiddenLayersTemp.findIndex(layer => {
            return layer.key === key
        })

        hiddenLayersTemp.splice(elementIndex + 1, 0, createHiddenLayerElement(0))
        
        hiddenLayersRef.current = hiddenLayersTemp
    }

    useEffect(() => {
        console.log('test')
        setHiddenLayers([...hiddenLayersRef.current])
    }, [hiddenLayersRef])

Но 'test' выводится только при запуске сайта, в дальнейшем, при вызове функции addLayer, useEffect не срабатывает. По какой причине так происходит и как это исправить?


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

Автор решения: Александр

useRef это не state а useEffect вызывается только когда происходят изменения в state или в зависимостях state которые переданы в массив зависимостей для useEffect.

const [counter, setCounter] = useState(1);

const addCounter = () => {
   setCounter(2); // эта функция вызывает `useEffect` так как `state` обновился.
}

_

const counter = useRef(1);

const addCounter = () => {
   counter.current = 2; // эта не вызывает `useEffect` так как в `state` нет изменений.
}

Пример: https://codesandbox.io/s/recursing-leaf-5cimg?file=/src/App.js

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

useEffect срабатывает, когда изменяется значение зависимости при очередном вызове . При этом проверяет только само значение, не делая ни shallow, ни deep сравнение переданного ему объекта. Т.е. в вашем случае он случае вызовется при изменении самого hiddenLayersRef.

А useRef в свою очередь, отдает вам на каждом вызове один и тот же объект.

Если вам нужно получить вызов эффекта при изменении hiddenLayersRef.current, то так и напишите:

useEffect(() => {
    console.log('test')
    setHiddenLayers([...hiddenLayersRef.current])
}, [hiddenLayersRef.current])

Кроме того, для вызова эффекта нужен вызов useEffect с новыми значениями зависимости, т.е. ре-рендер компонента. Т.е. код, меняющий hiddenLayersRef.current (вызывающий ваш addLayer(key)) должен прямо или триггерить ререндер или самого компонента, или его родителя. Нет вызова - нет реренера с новыми значениями зависимости - нет нового эффекта.

→ Ссылка