ReactJS Anti Pattern ~Passing Setters Down the Components Tree~

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MyrinNew
    Senior Member
    • Feb 2024
    • 5168

    #1

    ReactJS Anti Pattern ~Passing Setters Down the Components Tree~

    ・The following example allows a developer to pass the setter function directly to its child component.






    // Form.jsx
    function Form() {
    const [formData, setFormData] = useState({ name: '' });
    return (

    Form

    {/* Pass the setter function down to ChildComponent */}

    console.log(formData)}>Submit


    );
    };

    // Input.jsx
    function Input({ name, setFormData }) {
    const handleInputChange = (event) => {
    // Directly using the setFormData setter function from the parent
    setFormData((prevData) => ({ ...prevData, name: event.target.value }));
    };

    return (


    Name:




    );
    };







    Abstraction Leak

    ・An abstraction leak occurs when one component knows too much about another component's internal implementation. In this case, the Input component makes the following assumption:

    1. The parent component uses the useState hook.
    2. The state contains a name field directly, alongside other data.
    3. The parent will always remain in the same state.


    These assumptions create a tight coupling between the child and parent components, meaning any change to the parent's state structure or management mechanism requires an update to the child.


    Why is that so bad?

    -Fragility: Changes to the parent component's logic break the child component, creating a maintenance headache.


    -Reduced Reusability: The child is tied to a specific parent implementation, which limits its use in other contexts.


    -loss of Clarity: Using raw setState makes it unclear which part of the child component is supposed to be modified.


    How do we solve the leak?

    ・Solving the abstraction leak in this case is extremely simple. The Input component does not need to accept a prop with the actual setter function. Instead, it can receive a callback function that encapsulates the state change. For example, it could be a function named handleNameChange.






    // Form.jsx
    function Form() {
    const [formData, setFormData] = useState({ name: '' });
    const handleNameChange = (name) => {
    setFormData((prevState) => ({...prevState, name}));
    };

    return (

    Form

    {/* Pass the setter function down to Input */}

    console.log(formData)}>Submit


    );
    };

    // Input.jsx
    function Input({ name, onChange }) {
    const handleInputChange = (event) => {
    onChange(event.target.value);
    };

    return (


    Name:




    );
    };









    More...
Working...