Clashing useEffects?

Sep 22 2020

Eu sinto que encontro esse problema com frequência.

Ao encadear useEffects para serem acionados após mudanças de estado, descobri que alguns dos useEffects na cadeia têm dependências sobrepostas que fazem com que ambos sejam acionados em vez de sequencialmente, depois que um deles define o estado.

Exemplo: estou ativando uma cadeia de efeitos de uso ao chapterIndexatualizar.

let [ chapterIndex, setChapterIndex ] = useState<number | null>(0);

let [textTransitioning, setTextTransitioning] = useState<'out' | 'in' | null>(null);

useEffect(() => {
    setTextTransitioning('out')
}, [chapterIndex])

useEffect(() => {
    if (chapterIndex !== null) {
        const {
            current: chapter = null
        } = chapterRefs.current[chapterIndex];
            
        if (textTransitioning === 'in') {
            chapter?.classList.add('in');
        }
    }
}, [textTransitioning, chapterIndex])

Como faço para evitar que ambos sejam executados quando houver chapterIndexalterações? Só quero que o segundo useEffect seja executado depois que o primeiro useEffect for definido como textTransitioning. Ao remover chapterIndexda matriz de dependência, recebo o erro: 'React Hook useEffect tem uma dependência ausente:' capítuloIndex '. Inclua ou remova a matriz de dependência. '

Respostas

Itaywazana Sep 22 2020 at 09:54

useEffectleva 2 argumentos. a primeira é a função a ser chamada e a segunda é uma matriz de variáveis ​​chamada matriz de dependências. o segundo argumento usado para acionar o efeito de uso enquanto uma das variáveis ​​na matriz está mudando. então, se você não quiser useEffectser chamado quando uma variável específica for alterada, não a passe no array dependencies. seu código deve ser assim:

let [ chapterIndex, setChapterIndex ] = useState<number | null>(0);

let [textTransitioning, setTextTransitioning] = useState<'out' | 'in' | null>(null);

useEffect(() => {
      setTextTransitioning('out')
}, [chapterIndex])

useEffect(() => {
 if (chapterIndex !== null) {
     const {
         current: chapter = null
     } = chapterRefs.current[chapterIndex];
         
     if (textTransitioning === 'in') {
         chapter?.classList.add('in');
     }
 }
}, [textTransitioning]

Acho que não é muito eficiente fazer um useEffectdisparar o outro mas talvez eu não esteja vendo o quadro todo

YogeshChaturvedi Sep 22 2020 at 09:58

Você precisa remover "capítuloIndex" da matriz no segundo useEffect. Portanto, quando o primeiro useEffect for executado, ele atualizará o "textTransitioning" que causará o segundo gatilho useEffect.

Para obter mais execução condicional de useEffect, você pode consultar https://reactjs.org/docs/hooks-effect.html