skip to Main Content

I have a React funcion component with states initialized as below

const [selectedSection, setSelectedSection] = useState('section1');
const [section, setSection] = useState({
    section1: false,
    section2: false,
    section3: false
});

Now, on click/change of the section links, I invoke below;

const onSectionChange = (id) => {
    setSelectedSection(id);
}

useEffect(() => {
    // Below seems incorrect way of doing... Not sure what is the right way ??
    setSection({
        section1: false,
        section2: false,
        section3: false
    });
    setSection({...section, [selectedSection]: true});
}, [selectedSection]);

I want to pass the new selected section to my child component as below

<MyChildComponent section={section}>

For some reason, the correct state is not passed to MyChildComponent. I assume I am not setting setSection properly in my useEffect. What is the right way to handle this?

3

Answers


  1. From what you’ve described here. I think you can achieve your desired results without the use of two states, as I think it’s redundant to use two states for the same thing.

    const defaultSessions = {
        section1: false,
        section2: false,
        section3: false
    }
    
    const [section, setSection] = useState({...defaultSessions, section1: true});
    
    // Now, on click/change of the section links, I invoke below;
    const onSectionChange = (id) => {
        setSection(prev => ({...defaultSessions, [id]: true}))
    }
    
    <button onClick={() => onSectionChange('section1')} > Section 1 </button>
    <button onClick={() => onSectionChange('section2')} > Section 2 </button>
    <button onClick={() => onSectionChange('section3')} > Section 3 </button>
    

    You should not use useEffect hooks if not needed, as they will create unnecessary re-renders. As for the above code, when you click the link button, it will call the onSectionChange with the respective id. We can then directly change the main state, and turn the selected link value to true.

    Note that it is a good practice to use the above method to update a state, as we will get the current state value in the prev variable, which we can easily update and set the state to the update value.

    Also you were using setState one after other in the same function. Note that it won’t work like that. You should only set the state once in a scope.

    Login or Signup to reply.
  2. Maybe you could think of it in a differnt way:

    You’ve marked the selected section, which means that the other sections are always false, so you don’t need to mark the other sections as false, just use it directly.

    Here is an example:

    const mockSection = [
        {
            id: 'section1'
        },
        {
            id: 'section2'
        },
        {
            id: 'section3'
        },
        {
            id: 'section4'
        }
    ]
    
    const [selectedSection, setSelectedSection] = useState('section1');
    
    const onSectionChange = (id) => {
        setSelectedSection(id);
    }
    
    // ex.1
    const UlComponent = <ul>
        {
            mockSection.map( section => 
                <li class={section.id === selectedSection ? 'style-on':''} onClick="onSectionChange(section.id)">some thing</li>
            )
        }
    </ul>
    
    // ex.2
    const CheckComponent = <div>
        {
            mockSection.map( section => 
                <input type="checkbox" checked={section.id === selectedSection} onClick="onSectionChange(section.id)" />
            )
        }
    </div>
    

    This is the same for the child, just pass selectedSection.
    Logic first, Code last.

    <MyChildComponent selectedSection={selectedSection}></MyChildComponent>
    
    Login or Signup to reply.
  3. No Need to use two setState and useEffect, you can achieve this using one setState only.

         const defaultSection = {
           section1:false,
           section2:false,
           section3:false,
         }
    

    define this constant then you can modify the onSectionChange function.

         const onSectionChange = (id) => {
           setSection({
             ...defaultSection,
            [id]: true
        })
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search