Re render useLayoutEffect

У меня есть такой код:

import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'
import styles from './styles.module.css'
import { Header } from '../../../../modules/Header'
import RowRecomend from '../RowRecomend/RowRecomend'
import { ICard } from '../../../../components/Card/Card'
const HomeOutlet = () => {
  const ref=useRef<HTMLDivElement>(null)
  const [cards,setCards]=useState<ICard[]>([])
  const [firstCalculating, setFirstCalculating]=useState<boolean>(true)
  useLayoutEffect(()=>{
    if(firstCalculating && ref.current){
      const howCards=Math.floor(ref.current.clientWidth/178)
      for(let i=0; i<howCards;i++){
        setCards((prev)=>[...prev,{song:'Bank Account',artist:'21 savage',img:''}])
      }
      setFirstCalculating(false)
    }
  },[])
  

  return (
    <div className={styles.wrap} ref={ref}>
      <Header/>
      <RowRecomend title='Great first audiobooks' cards={cards}/>
      <RowRecomend title='Что-то новенькое' cards={cards}/>
    </div>
  )
}

export default HomeOutlet

Я не понимаю почему у меня код внутри проверки в useLayoutEffect выполняется два раза, я знаю, что у меня стоит strict mode, но у меня есть ограничитель firstCalculating, даже если я поставлю в массив зависимостей firstCalculating, все равно будет выполняться два раза, даже если я сменю useLayoutEffect на useEffect.


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

Автор решения: Oliver Patterson

Вам нужно создать ref что-то типо const isFristRenderRef = useRef<boolean>(true) и в useLayoutEffect проверять, если он false - делаем return, иначе мы выставляем для isFristRenderRef.current = false и делаем остальной код.

Итоговый код будет таким:

import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
import styles from './styles.module.css';
import { Header } from '../../../../modules/Header';
import RowRecomend from '../RowRecomend/RowRecomend';
import { ICard } from '../../../../components/Card/Card';

const HomeOutlet = () =>
{
    const isFirstRenderRef = useRef<boolean>(true)
    const ref = useRef<HTMLDivElement>(null);
    
    const [ cards, setCards ] = useState<ICard[]>([]);

    useLayoutEffect(() =>
    {
        if (ref.current === null || isFirstRenderRef.current === false)
        {
            return;
        }

        isFirstRenderRef.current = false;

        const howCards = Math.floor(ref.current.clientWidth / 178);
        for (let i = 0; i < howCards; i++)
        {
            setCards((prev) => [ ...prev, { song: 'Bank Account', artist: '21 savage', img: '' } ]);
        }
    }, []);


    return (
        <div className={styles.wrap} ref={ref}>
            <Header />
            <RowRecomend title='Great first audiobooks' cards={cards} />
            <RowRecomend title='Что-то новенькое' cards={cards} />
        </div>
    );
};

export default HomeOutlet;
→ Ссылка