0
votes

This is my first react project and I'm pretty sure I'm not managing state correctly but I don't know what to "google" for learning a better approach.

I have a parent / child component interaction. The parent passes a true or false to the child depending on user selection on the parent. The user can also make a choice in the child component (when visible) to change that same true or false variable.

I'm pretty sure I want to only manage that true / false state on the parent but I haven't been able to discover how to do that. This is the best I have come up with. On initial load everything works properly but subsequent interactions the parent no longer communicates with the child.

Parent Component

const App = ()=> {

   const [drawerVisible, setDrawerVisible]  = useState<boolean>(false);
   //useEffect(() => { setDrawerVisible(drawerVisible)}, [drawerVisible] )

   const showDrawer = () => {
      console.log('App show drawer before: ' + drawerVisible);
      setDrawerVisible(true);
      console.log('App drawer after: ' + drawerVisible)
   };

return <Layout>
<UserDrawer drawerVisible={drawerVisible} />

</Layout>
};

export default App;

Child Component

interface DrawerVisible {
   drawerVisible:boolean
}

const UserDrawer = ({drawerVisible}:DrawerVisible) => {
console.log('child passed in: ' + drawerVisible);

const [drawerHidden, setDrawerHidden]  = useState<boolean>(drawerVisible);
useEffect(() => { setDrawerHidden(drawerVisible)}, [drawerVisible] )

const onClose = () => {
    setDrawerHidden(false);
};

  return <Drawer
    title="User Details"
    placement={'right'}
    closable={true}
    onClose={onClose}
    visible={drawerHidden}
    getContainer={false}
    style={{ position: 'absolute' }}
  >
    <Logout />
  </Drawer>
}

export default UserDrawer;

As I mentioned on initial load everything works. The console log shows correct values and the drawer shows.

Console Log

App show drawer before: false
App.tsx:47 App drawer after: false
UserDrawer.tsx:10 child passed in: true
UserDrawer.tsx:10 child passed in: true
//Not sure why UserDrawer is being called twice?

However subsequent interactions never get passed to the child?

Console Log

//Clicked show drawer button 3 times
App show drawer before: true
App.tsx:47 App drawer after: true

App.tsx:45 App show drawer before: true
App.tsx:47 App drawer after: true

App.tsx:45 App show drawer before: true
App.tsx:47 App drawer after: true

Any help getting my nose pointed inthe right direction would be much appreciated.

TIA

1
@ankit-sanghvi Thank You! I knew I needed to manage state in one place but didn't know I could pass the parent useState to the child. Very cool. Thank you again.GPGVM

1 Answers

1
votes

The reason this is happening is because you are controlling the same state from 2 different places. A simple solution would be to pass the setDrawerVisible also into your child component & use it there

The code for that is here

Parent Component

const App = ()=> {

   const [drawerVisible, setDrawerVisible]  = useState<boolean>(false);

   const showDrawer = () => {
      console.log('App show drawer before: ' + drawerVisible);
      setDrawerVisible(true);
      console.log('App drawer after: ' + drawerVisible)
   };

return <Layout>
    <UserDrawer drawerVisible={drawerVisible} setDrawerVisible={setDrawerVisible} />
  </Layout>
};

export default App;

Child Component

interface DrawerVisible {
   drawerVisible:boolean
   setDrawerVisible:Dispatch<SetStateAction<boolean>>
}

const UserDrawer:React.FC<DrawerVisible> = ({drawerVisible, setDrawerVisible}) => {

  const onClose = () => setDrawerVisible(false);

  return <Drawer
    title="User Details"
    placement={'right'}
    closable={true}
    onClose={onClose}
    visible={drawerVisible}
    getContainer={false}
    style={{ position: 'absolute' }}
  >
    <Logout />
  </Drawer>
}