Using useEffect in React to Promote Component Reusability

The React documentation describes how to conveniently and effectively manage state changes in your components by passing handlers through props. This helps avoid overengineering and promotes component reusability. However, this often leads to increased complexity in the root component.

Consider the provided diagram, showing a simple component hierarchy with Root, Child A, Child B, and Child C. Child C contains logic that is functionally independent from the other tasks of the Root component. However, to function correctly, Child C requires a prop that is modified by Child B.

Child A and Child B use handlers passed through props. Child B changes a prop (e.g., counter), passes it to Child A, which in turn passes it to the Root component. This approach is by the book and is correct.

Now, Child C uses useEffect to respond to changes in the prop (e.g., counter) and to handle the necessary logic to continue functioning correctly.

Problem Statement and Discussion

It’s understandable that this use of useEffect might raise concerns, suggesting that the states within Child C should be moved to the Root component to avoid using useEffect. This is generally correct as it can eliminate the side-effect. According to React documentation, this can be managed properly.

Advantages of the Current Structure

  1. Decoupling and Complexity:
  • Keeping the logic within Child C ensures that it remains independent
    and maintainable.
  • The Root component is not overloaded with additional logic, which keeps it simpler and more maintainable.
  1. Reusability:
  • Child C remains reusable because it is not tightly coupled with the Root component.
  • Strong coupling would mean Child C now requires multiple props (e.g., prop.min, prop.max, and prop.counter), complicating its use and reducing reusability.

Code Example

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>// Root Component
function Root() {
const [counter, setCounter] = useState(0);
const [globalSetting, setGlobalSetting] = useState(true);
const incrementCounter = () => setCounter(counter + 1);
const toggleGlobalSetting = () => setGlobalSetting(prev => !prev);
return (
<div>
<ChildA counter={counter} incrementCounter={incrementCounter} />
<ChildC counter={counter} globalSetting={globalSetting} />
</div>
);
}
// ChildA Component
function ChildA({ counter, incrementCounter }) {
return (
<div>
<ChildB incrementCounter={incrementCounter} />
</div>
);
}
// ChildB Component
function ChildB({ incrementCounter }) {
return (
<button onClick={incrementCounter}>Increment</button>
);
}
// ChildC Component
function ChildC({ counter, globalSetting }) {
const [localState, setLocalState] = useState(null);
const [anotherLocalState, setAnotherLocalState] = useState(false);
useEffect(() => {
// Logic to handle change in counter
console.log("Counter changed:", counter);
// Updating local state based on counter change
setLocalState(counter * 2);
}, [counter]);
useEffect(() => {
// Logic to handle change in globalSetting
console.log("Global setting changed:", globalSetting);
// Updating another local state based on globalSetting change
setAnotherLocalState(globalSetting);
}, [globalSetting]);
return (
<div>
<div>Counter: {counter}</div>
<div>Local State: {localState}</div>
<div>Another Local State: {anotherLocalState ? "True" : "False"}</div>
</div>
);
}
</code>
<code>// Root Component function Root() { const [counter, setCounter] = useState(0); const [globalSetting, setGlobalSetting] = useState(true); const incrementCounter = () => setCounter(counter + 1); const toggleGlobalSetting = () => setGlobalSetting(prev => !prev); return ( <div> <ChildA counter={counter} incrementCounter={incrementCounter} /> <ChildC counter={counter} globalSetting={globalSetting} /> </div> ); } // ChildA Component function ChildA({ counter, incrementCounter }) { return ( <div> <ChildB incrementCounter={incrementCounter} /> </div> ); } // ChildB Component function ChildB({ incrementCounter }) { return ( <button onClick={incrementCounter}>Increment</button> ); } // ChildC Component function ChildC({ counter, globalSetting }) { const [localState, setLocalState] = useState(null); const [anotherLocalState, setAnotherLocalState] = useState(false); useEffect(() => { // Logic to handle change in counter console.log("Counter changed:", counter); // Updating local state based on counter change setLocalState(counter * 2); }, [counter]); useEffect(() => { // Logic to handle change in globalSetting console.log("Global setting changed:", globalSetting); // Updating another local state based on globalSetting change setAnotherLocalState(globalSetting); }, [globalSetting]); return ( <div> <div>Counter: {counter}</div> <div>Local State: {localState}</div> <div>Another Local State: {anotherLocalState ? "True" : "False"}</div> </div> ); } </code>
// Root Component
function Root() {
 const [counter, setCounter] = useState(0);
 const [globalSetting, setGlobalSetting] = useState(true);

 const incrementCounter = () => setCounter(counter + 1);
 const toggleGlobalSetting = () => setGlobalSetting(prev => !prev);

 return (
   <div>
     <ChildA counter={counter} incrementCounter={incrementCounter} />
     <ChildC counter={counter} globalSetting={globalSetting} />
   </div>
 );
}

// ChildA Component
function ChildA({ counter, incrementCounter }) {
 return (
   <div>
     <ChildB incrementCounter={incrementCounter} />
   </div>
 );
}

// ChildB Component
function ChildB({ incrementCounter }) {
 return (
   <button onClick={incrementCounter}>Increment</button>
 );
}

// ChildC Component
function ChildC({ counter, globalSetting }) {
 const [localState, setLocalState] = useState(null);
 const [anotherLocalState, setAnotherLocalState] = useState(false);

 useEffect(() => {
   // Logic to handle change in counter
   console.log("Counter changed:", counter);
   // Updating local state based on counter change
   setLocalState(counter * 2);
 }, [counter]);

 useEffect(() => {
   // Logic to handle change in globalSetting
   console.log("Global setting changed:", globalSetting);
   // Updating another local state based on globalSetting change
   setAnotherLocalState(globalSetting);
 }, [globalSetting]);

 return (
   <div>
     <div>Counter: {counter}</div>
     <div>Local State: {localState}</div>
     <div>Another Local State: {anotherLocalState ? "True" : "False"}</div>
   </div>
 );
}

Conclusion

Deciding whether to keep the logic in Child C or move it to the Root component requires careful consideration. The reusability and maintainability of the components should be prioritized. Using useEffect in Child C keeps the component independent and reusable, while not unnecessarily complicating the Root component.

I thought it would be a good idea to have a discussion about the “it depends”-factor of this.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật