Sửa lỗi "Cannot update a component from inside the function body of a different component" trong React

intermediate⚛️ React2026-03-19| React 16.13+, React 17, React 18 — mọi hệ điều hành, mọi bundler (Vite, CRA, Next.js)

Error Message

Cannot update a component from inside the function body of a different component.
#react#cập nhật-state#lifecycle#side-effect

Nguyên Nhân Gây Ra Lỗi NàyMở console trình duyệt lên và bạn sẽ thấy thông báo này:

Warning: Cannot update a component from inside the function body of a different component.

React phát hiện rằng trong giai đoạn render của component A, có gì đó đã kích hoạt cập nhật state ở component B. Quá trình render phải thuần túy — không có side effect, không có mutation state. Việc cập nhật state chéo giữa các component bị cấm trong giai đoạn này. Ba pattern sau chiếm phần lớn các trường hợp xảy ra lỗi:

  • Một component con gọi hàm setter state của component cha (được truyền qua prop) trực tiếp bên trong phần thân render- Một Redux hoặc Context action được dispatch trong quá trình render- Một custom hook gọi callback đồng bộ trong quá trình render, không nằm trong useEffect## Tái Hiện LỗiVí dụ tối giản sau sẽ kích hoạt cảnh báo một cách đáng tin cậy:
// Parent.jsx
function Parent() {
  const [status, setStatus] = useState('idle');

  return (
    <div>
      <p>Status: {status}</p>
      <Child onReady={() => setStatus('ready')} />
    </div>
  );
}

// Child.jsx — BỊ LỖI
function Child({ onReady }) {
  onReady(); // <-- được gọi trong quá trình render, cập nhật state của Parent
  return <div>Child content</div>
}

Khi Child render, nó gọi onReady() ngay lập tức. Lời gọi đó tác động đến setStatus bên trong Parent. React bắt được điều này và ném ra cảnh báo.

Cách Sửa Nhanh: Chuyển Lời Gọi Vào useEffectBọc lời gọi trong useEffect — nó chạy sau khi render, không phải trong lúc render:

// Child.jsx — ĐÃ SỬA
import { useEffect } from 'react';

function Child({ onReady }) {
  useEffect(() => {
    onReady();
  }, []); // chạy một lần sau lần render đầu tiên

  return <div>Child content</div>
}

Side effect đã được đưa ra khỏi giai đoạn render. onReady được gọi sau khi mount — đúng chỗ nó cần ở. Chú ý mảng dependency. Nếu onReady được tạo lại sau mỗi lần render của component cha, effect này sẽ chạy trong vòng lặp. Hãy ổn định nó bằng useCallback ở component cha:

// Parent.jsx
const handleReady = useCallback(() => {
  setStatus('ready');
}, []);

<Child onReady={handleReady} />

Sửa Lỗi Redux / Context Dispatch Trong Quá Trình RenderDispatch bên trong phần thân component là lỗi tương tự, chỉ khác cú pháp:

// BỊ LỖI
function NotificationBadge({ hasNew }) {
  if (hasNew) {
    dispatch(markAsSeen()); // <-- trong quá trình render!
  }
  return <span>{hasNew ? 'New' : ''}</span>
}

// ĐÃ SỬA
function NotificationBadge({ hasNew }) {
  useEffect(() => {
    if (hasNew) {
      dispatch(markAsSeen());
    }
  }, [hasNew, dispatch]);

  return <span>{hasNew ? 'New' : ''}</span>
}

Sửa Lỗi Callback Thông Báo Cho Component Cha Trong Quá Trình RenderMột phiên bản tinh tế hơn: component con gọi prop callback có điều kiện trong quá trình render để thông báo cho component cha về một trạng thái nội bộ nào đó. Trông có vẻ vô hại. Nhưng không phải vậy:

// BỊ LỖI — callback cập nhật state của component cha trong quá trình render của Dropdown
function Dropdown({ isOpen, onStateChange }) {
  if (isOpen) {
    onStateChange('open'); // kích hoạt cập nhật state ở một component khác
  }
  return <div>...</div>
}

// ĐÃ SỬA
function Dropdown({ isOpen, onStateChange }) {
  useEffect(() => {
    onStateChange(isOpen ? 'open' : 'closed');
  }, [isOpen, onStateChange]);
  return <div>...</div>
}

Đáng lưu ý: việc cập nhật state của chính component trong quá trình render là câu chuyện khác. React cho phép điều này, miễn là bạn dùng điều kiện bảo vệ:

// OK — cập nhật state của chính mình với điều kiện bảo vệ (thay thế hooks cho getDerivedStateFromProps)
function Dropdown({ isOpen }) {
  const [open, setOpen] = useState(false);
  if (isOpen !== open) {
    setOpen(isOpen); // React render lại ngay lập tức, bỏ qua commit trạng thái trung gian
  }
  return <div>...</div>
}

React render lại component ngay lập tức mà không commit trạng thái trung gian. Chỉ việc cập nhật state của component khác mới bị cấm trong quá trình render.

Sửa Lỗi Custom Hook Gọi Callback Trong Quá Trình RenderCustom hook có thể che giấu vấn đề tương tự. Khi một hook gọi callback bên trong phần thân hook thay vì trong useEffect, bạn sẽ nhận được cùng cảnh báo — chỉ là khó phát hiện hơn:

// Custom hook bị lỗi
function useDataLoader(onLoad) {
  const data = fetchFromCache();
  if (data) {
    onLoad(data); // gọi trong quá trình render!
  }
  return data;
}

// Custom hook đã sửa
function useDataLoader(onLoad) {
  const data = fetchFromCache();
  useEffect(() => {
    if (data) {
      onLoad(data);
    }
  }, [data, onLoad]);
  return data;
}

Kiểm Tra Sau Khi Sửa- Mở DevTools trình duyệt → tab Console.- Tải lại trang và thực hiện thao tác gây ra cảnh báo.- Cảnh báo Cannot update a component... phải biến mất.- Xác nhận component vẫn hoạt động đúng — các cập nhật state vẫn xảy ra, chỉ là sau khi render thay vì trong lúc render.- Nếu bạn dùng React DevTools Profiler, hãy kiểm tra flame graph để phát hiện các vòng lặp re-render không mong muốn sau khi sửa.## Tóm Tắt- Giai đoạn render phải thuần túy. Không có cập nhật state ảnh hưởng đến component khác.- Chuyển tất cả các cập nhật state chéo component vào useEffect với mảng dependency chính xác.- Bọc prop callback trong useCallback ở component cha để giữ tham chiếu ổn định.- Redux/Context: không bao giờ dispatch trong quá trình render. Hãy dùng effect hoặc event handler.- Cập nhật state của chính component trong quá trình render được phép khi có điều kiện bảo vệ. Cập nhật state của component khác thì không được phép.

Related Error Notes