useEffectsの衝突?

Sep 22 2020

私はこの問題に頻繁に遭遇するように感じます。

状態の変更後にトリガーされるuseEffectsをチェーンすると、チェーン内のuseEffectの一部に重複する依存関係があり、1つが状態に設定された後、両方が順次ではなくトリガーされることがわかります。

例:chapterIndex更新時にuseEffectsのチェーンをトリガーしています。

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])

chapterIndex変更時に両方が実行されないようにするにはどうすればよいですか?最初のuseEffectがtextTransitioningに設定された後にのみ、2番目のuseEffectを実行したいと思います。chapterIndex依存関係の配列から削除すると、次のエラーが発生します:'React Hook useEffectに依存関係がありません:' chapterIndex '。それを含めるか、依存関係配列を削除してください。

回答

Itaywazana Sep 22 2020 at 09:54

useEffect2つの引数を取ります。1つ目は呼び出す関数で、2つ目は依存関係配列と呼ばれる変数の配列です。配列内の変数の1つが変更されているときに、使用効果をトリガーするために使用される2番目の引数。したがってuseEffect、特定の変数が変更されたときに呼び出されたくない場合は、依存関係の配列に渡さないでください。コードは次のようになります。

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]

useEffect一方が他方をトリガーするのはあまり効率的ではないと思いますが、全体像が見えていない可能性があります

YogeshChaturvedi Sep 22 2020 at 09:58

2回目のuseEffectで、配列から「chapterIndex」を削除する必要があります。したがって、最初のuseEffectが実行されると、2番目のuseEffectトリガーを引き起こす「textTransitioning」が更新されます。

useEffectのより条件付きの実行については、参照できます https://reactjs.org/docs/hooks-effect.html