Галоўная / Артыкулы

Не трэба ўсё час паводлівацца useEffect для кожнай проблемы ў React.

useEffect выкорыстоўваецца для сінхронізаціі з зовнішнімі сістэмамі. У React значэнні неабходна вылучаць пад час атрыбутавання элемента, кераваць клікамі праз адпаведныя змаганні, а таксама запрашваць рэальныя даны за дапамою спецыяльных інструментаў, а не праз useEffect.

Выдавец: REACTAPP.TOP6 хв чытання1424 слоў

Крыніцы: Why I Stopped Using `useEffect` for Everything in My React Apps

Пастка useEffect

Учэбнікі, які вівучаюць хукі, частаўка ўжываюць useEffect для запрашэння дадзеных, стварэння пахаванага статаусу і адпаведных дзеянняў пад час нажатка на кнопкі. Эфекты сінхронізуюцца з зовнішнімі сістэмамі — яны не ўжываюцца як стандартны інструмент для звычайной логікі атрыбутавання элементаў.

Што на самай працэ практыкуе useEffect

Пасля атрыбутавання элементаў React запускае эфекты, каб прыўязаць слухачы, ачысці цяпі зв’язку чыў імператывна выканаць дзеяння за межамі React. Неправільны ўжытак вызывае проблемы у відобразэнні, двойныя запрашэння дадзеных чыў багі, зв’язаныя з конкурэнцыей.

// ❌ BAD: Two renders, unnecessary state
function UserProfile({ firstName, lastName }) {
  const [fullName, setFullName] = useState('');
useEffect(() => {
    setFullName(`${firstName} ${lastName}`);
  }, [firstName, lastName]);
  return <h1>{fullName}</h1>;
}
// ✅ GOOD: Calculate during render
function UserProfile({ firstName, lastName }) {
  const fullName = `${firstName} ${lastName}`;
return <h1>{fullName}</h1>;
}
// ❌ BAD: Unnecessary effect + state
function ProductList({ products }) {
  const [sortedProducts, setSortedProducts] = useState([]);
useEffect(() => {
    const sorted = [...products].sort((a, b) => a.price - b.price);
    setSortedProducts(sorted);
  }, [products]);
  return (
    <ul>
      {sortedProducts.map(product => (
        <li key={product.id}>{product.name} - ${product.price}</li>
      ))}
    </ul>
  );
}
// ✅ GOOD: Calculate during render (useMemo for expensive ops)
function ProductList({ products }) {
  const sortedProducts = useMemo(() => {
    return [...products].sort((a, b) => a.price - b.price);
  }, [products]);
return (
    <ul>
      {sortedProducts.map(product => (
        <li key={product.id}>{product.name} - ${product.price}</li>
      ))}
    </ul>
  );
}
// ❌ BAD: Manual fetching with useEffect
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
useEffect(() => {
    let cancelled = false;
    async function fetchUser() {
      try {
        setLoading(true);
        const response = await fetch(`/api/users/${userId}`);
        if (!response.ok) throw new Error('Failed to fetch');
        const data = await response.json();
        if (!cancelled) setUser(data);
      } catch (err) {
        if (!cancelled) setError(err.message);
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    fetchUser();
    return () => { cancelled = true; };
  }, [userId]);
  if (loading) return <Spinner />;
  if (error) return <p>Error: {error}</p>;
  return <div>{user.name}</div>;
}
// ✅ GOOD: Use TanStack Query (React Query)
import { useQuery } from '@tanstack/react-query';
function UserProfile({ userId }) {
  const { data: user, isPending, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
  });
  if (isPending) return <Spinner />;
  if (error) return <p>Error loading user</p>;
  return <div>{user.name}</div>;
}
// ❌ BAD: Overcomplicating with useEffect
function LikeButton({ postId }) {
  const [liked, setLiked] = useState(false);
useEffect(() => {
    if (liked) {
      fetch(`/api/posts/${postId}/like`, { method: 'POST' });
    } else {
      fetch(`/api/posts/${postId}/unlike`, { method: 'POST' });
    }
  }, [liked, postId]);
  return (
    <button onClick={() => setLiked(!liked)}>
      {liked ? '❤️' : '🤍'}
    </button>
  );
}
// ✅ GOOD: Handle in the event handler
function LikeButton({ postId }) {
  const [liked, setLiked] = useState(false);
const handleLike = async () => {
    const newLiked = !liked;
    setLiked(newLiked);
    await fetch(`/api/posts/${postId}/${newLiked ? 'like' : 'unlike'}`, {
      method: 'POST',
    });
  };
  return (
    <button onClick={handleLike}>
      {liked ? '❤️' : '🤍'}
    </button>
  );
}
function WindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);

    // Cleanup is crucial!
    return () => window.removeEventListener('resize', handleResize);
  }, []);
  return <p>Window width: {width}px</p>;
}
function ChatRoom({ roomId }) {
  const [messages, setMessages] = useState([]);
useEffect(() => {
    const connection = createWebSocketConnection(roomId);

    connection.onMessage = (msg) => {
      setMessages(prev => [...prev, msg]);
    };
    connection.connect();
    return () => {
      connection.disconnect(); // Cleanup!
    };
  }, [roomId]);
  return <MessageList messages={messages} />;
}
function ChartComponent({ data }) {
  const chartRef = useRef(null);
  const chartInstance = useRef(null);
useEffect(() => {
    if (chartRef.current && !chartInstance.current) {
      chartInstance.current = new ChartLibrary(chartRef.current, {
        type: 'line',
        data: data,
      });
    }
    return () => {
      chartInstance.current?.destroy();
      chartInstance.current = null;
    };
  }, []);
  return <canvas ref={chartRef} />;
}
function PageTitle({ title }) {
  useEffect(() => {
    document.title = `${title} | My App`;

    return () => {
      document.title = 'My App'; // Reset on unmount
    };
  }, [title]);
return null;
}

Чатыры распашчастыя памылкі

1. Вычысленне значэнняў у эфектах

Вырахоўваецца пад час атрыбутавання (або useMemo, калі гэта дорога процедура). Эфекты, якія змяняюць setState на адварыянтах/стане, часта створуюць забраныя ціклі зворачнай связі.

2. Дарогі вырахункі ў эфектах

Чыстыя вырахункі трэба выпрацоўваць пад час атрыбутавання/захавання, а не пасля атрыбутавання элементаў.

3. Зялленне дадзеных як неактуальны эфект

Практыка зяллення дадзеных трэба супакоўваць за дапамогою функцый анулювання, кэшавання і правільнага адпрацоўвання памылак. Лепш выкарыстоваць спецыяльныя бібліятэкі чыстаўкі з механізмамі керавання станом завантажэння; калі выкарыстоўваюцца эфекты, трэба кераваць працэсамі анулювання і супернечкамі.

4. Дзеяння корыстувальца ў эфектах

Функцыі обработкі кліка павінны знаходзіцца ў адпрацоўкі запуску змян. Эфекты, якія запускаюцца пасля змены стану на адварыянтах кліка, створуюць непрамасць і багі.

Дрэва адлічэння

Калі процедура вырахоўваецца на адварыянтах стану/параметрах → атрыбутавання. Калі яна рэагуе на клік/надсылку даных → адпрацоўка запуску змян. Калі яна взаімаецца з API DOM, канектам да сеткі чыстаўкі трэціх сторон → эфект.

Калі эфекты ўжоць

Зовнішнія слухальнікі

WebSockets

Ініцыявацыя бібліятэкаў трохі чужых сторон

Імператыўныя API, якія не ўскладненыя React і якія павінны чыста завершваць свою працу

Заканчэнне

Менш эфектаў, яснейшы прайом дадзеных. Адкладзіце useEffect для сінхронізацыі з сістэмамі за межамі React — не як стандартны інструмент для кожной думкі пасля атрыбутавання.

Рэжым строгасці два разы запускае эфекты пад час розработы, ўбачваючы недастатковую чыстку — спрыяйце гэтаму пад час налагоджэння сокетаў. Вядомыя бібліятэкі дадзеных лепш паслужаюць для стану сервера, калі компоненты опісваюць залежнасці, а не самі ствараюць эфекты фетча. Абмэжыцеся мерамі пры дадаванні эфектаў, якія толькі копіююць атрыбуты ў стан; такі падход часта ёсць неправільным разуменням працэсу атрыбутавання.

Функцыі чысткі павінны знішчаць слухальнікі і таймеры; застойныя працоўнікі ёсцю класычным джэрэлам паведамленняў пра змену стану пасля зняцья компонента.

Масівы залежнасцей ўскладненыя частка кантракту — калі прыховаць значэння, з’являюцца застарэлыя клозуры; калі занадта многа аб’ектаў і эфектаў у спіску, кожная перрадарыце створвае проблемы.

Пад час сінхронізацыі з параметрамі пошуку URL або зовнішнімі хранальнямі, лепей выбіраць спецыяльна створаныя хукі, якія інкапсулююць межы эфектаў.

Аплікацыі, якія перрадаруюцца на серверэ, не должны запускаць эфекты, якія працуюць толькі ў браузеры, без адпаведных захоўнаў; трэба кераваць імі на адпаведным етапе сістэмы чы роце жыцця аплікацыі.

Функцыі чысткі павінны знімаць слухачы і таймеры; засталелыя обработчыкі ёсць класычным выварам паведамленняў пра зміну стану аплікацыі пасля ўсуненняя з экрана.

Масівы залежнасцей ўскладненыя частка кантракту — калі прыховаць значэння, з’являюцца застарэлыя клозуры; калі занадта многа аб’ектаў і эфектаў у спіску, кожная перрадарыце створвае проблемы.

Пад час сінхронізацыі з параметрамі пошуку URL або зовнішнімі хранальнямі, лепей выбіраць спецыяльна створаныя хукі, якія інкапсулююць межы эфектаў.

Програмы, які рэндаруюцца на серверэ, не должны запускаць эфекты, які працуюць толькі у браузеры, без захоўнікаў; неабходна рэгулювацыя па супакой чы ў цікле жыцця.

Функцыі чысткі павінны знімаць аслухальнікі і таймеры; застойныя апрацоўшчыкі ўсё чашчэ стаюць прычыной апавешчэнняў про зміны стану пасля завершэння рэндараўвання.

Масівы залежнасцяў ёсць часткай кантракту — калі прыховаць значэння, з’являюцца застарэлыя функціі; калі перэлічыць занадта многа об’ектаў і эфектаў, кожны рэндар стане медленым.

Пад час сінхронізацыі з параметрамі пошуку URL чы зовнішнімі хранальнямі крашчэ вжываць спецыяльныя хукі, якія інкапсулююць межы дзейства.

Програмы, які рэндаруюцца на серверэ, не должны запускаць эфекты, які працуюць толькі у браузеры, без захоўнікаў; неабходна рэгулювацыя па супакой чы ў цікле жыцця.

Функцыі чысткі павінны знімаць аслухальнікі і таймеры; застойныя апрацоўшчыкі ўсё чашчэ стаюць прычыной апавешчэнняў про зміны стану пасля завершэння рэндараўвання.

Масівы залежнасцей ўскладненыя частка кантракту — калі прыховаць значэння, з’являюцца застарэлыя клозуры; калі занадта многа аб’ектаў і эфектаў у спіску, кожная перрадарыце створае проблемы.

Пад час сінхронізацыі з параметрамі пошуку URL або зовнішнімі хранальнямі, лепей выбіраць спецыяльна створаныя хукі, якія інкапсулююць межы дзейнасці эфектаў.

Аплікацыі, якія перрадаруюцца на серверэ, не должны запускаць эфекты, якія працуюць толькі ў браузеры, без адпаведных захоўнаў; трэба кераваць імі на адпаведным етапе сістэмнага жыццёвага цыклу.

Функціі чысткі павінны знімаць слухачы і таймеры; засталелыя апрацоўшчыкі ўсё чашчэ стаюць прычыной апавешчэнняў про зміны стану пасля завершэння работы аплікацыі.

Масівы залежнасцей ўскладненыя частка кантракту — калі прыховаць значэння, з’являюцца застарэлыя клозуры; калі занадта многа аб’ектаў і эфектаў у спіску, кожная перрадарыце створае проблемы.

Пад час сінхронізацыі з параметрамі пошуку URL або зовнішнімі хранальнямі, лепей выбіраць спецыяльна створаныя хукі, якія інкапсулююць межы дзейнасці эфектаў.

Програмы, які рэндаруюцца на серверэ, не должны запускаць эфекты, які працуюць толькі у браузеры, без захоўнікаў; неабходна рэгулювацыя па супакой чы ў жыцёвым цыкле.

Функціі чысткі павінны знішчаць слухачыў і таймеры; застойныя апрацоўшчыкі ёсць класычным выварам паведамленняў про змену стану пасля зняцья компонента.

Масівы залежнасцяў ёсць часткай кантракту — калі прыховаць значэння, з’являюцца застарэлыя клозуры; калі занадта многа аб’ектаў і эфектаў у масіве, кожны рэндэр становіцца вялікай навантажэнням.

Пад час сінхронізацыі з параметрамі пошуку URL чы зовнішнімі хранальнямі, лепшая вжываць спецыяльныя хукі, які інкапсулююць межы дзейства.

Програмы, які рэндаруюцца на серверэ, не должны запускаць эфекты, які працуюць толькі у браузеры, без захоўнікаў; неабходна рэгулювацыя па супакой чы ў жыцёвым цыкле.

Функціі чысткі павінны знішчаць слухачыў і таймеры; застойныя апрацоўшчыкі ёсць класычным выварам паведамленняў про змену стану пасля зняцья компонента.

Масэвы залежнасцей ўскладненыя частка кантракту — калі прыховаць значэння, з’являюцца застарэлыя клозуры; калі перапісаць масэв об’ектаў, кожная перрадзіцель стане медленней.

Пры сінхронізацыі з параметрамі пошуку URL або зовнішнімі сховішчамі лепей вжываць спецыяльна створаныя хукі, якія інкапсулююць межы вплыву на стан.

Аплікацыі, якія перрадзяюцца на серверэ, не должны запускаць эфекты, якія працуюць толькі ў браузеры, без адпаведных захоўнаў; трэба кераваць імі на адзеўнай стадыі жыццёвага цыклу.

Функціі чысткі павінны абрываць слухачы і таймеры; засталія обработчыкі ёсць класычным выкарыстоўваннем паведамленняў про зміну стану пасля завершэння работы компонента.