2

I’m learning React, and I’m missing the possibility of my child components having their own properties and state which can be accessed by their container.

I’m struggling to find a good solution for this problem: I want to build a standard site layout with a sidebar (maybe one in each side). I’d like the sidebars to be collapsible by click of buttons that will be positioned elsewhere (for simplicity, let’s position the buttons on the same level of the sidebars – but outside them). Something like this:

    <div className="container">
      <SideNav name="Nirvana" side="left"/>
      <button> Open Left</button>
      <div className="content">I'm full!!!</div>
      <button>Open Right</button>    
      <SideNav name="Beatles" side="right"/>
    </div>

To do the 'collapsible thing' works, the container needs to know the width of the sidebars (at least by the css techniques that I researched). I want the container to grab this information (the widths) directly from the SideBars, because only them know what will be rendered inside them…

But from what I understood, this is a model that React wasn’t tailored for. Is it right? How should I deal with this problem from a React approach?

I know that one possible way is to pass callbacks to the child component. It seems ok for values that will be captured by the child (like a text field being filled by the user). But for values that 'born' with the child seems pretty strange (and too verbose)...

I'm looking for something else. Maybe another way to structure the components or something like that.

Below I’ll present the workaround that I did, but it doesn’t look like something that will escalate well:

To make the properties of the child components available for the parent (the container), I created this on the container:

const childProps = {};
function getprops(comp_id, comp_props)
{
  childProps[comp_id] = comp_props;
  return comp_id;
}

I pass the function getprops for the ‘components of interest’:

<SideNav name="Nirvana" width={widLeft} closeNav={closeSidenav} side="left"  getprops={function (p) {return getprops('leftnav', p);}}/>

And they will call it passing their internal state:

const myProps = {width: 240, side: props.side};
const myId = props.getprops(myProps);

And that's it.

2 Answers2

1

NOTE:

  • Top-to-bottom communication: Any type of data can used
  • Bottom-to-top communication: Only callback can be used

This solution works if you have a very simple use case. But if you have a more complex use case, then you should use the context or any state management library like redux, mobx, etc.

const Parent = () => {
    const [state, setState] = React.useState(0);
    const handleClick = (val) => setState(val);
    return (
      <div>
        <h1>Parent: {state}</h1>
        <Child onClick={handleClick} state={state} />
      </div>
    );
};

const Child = (props) => {
    const handleClick = () => props.onClick(props.state + 1);;
    return <h2 onClick={handleClick}>Child: {props.state}</h2>;
};

// Render it
ReactDOM.render(<Parent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

<div id="root"></div>
Rahul Sharma
  • 9,534
  • 1
  • 15
  • 37
  • I'll study Redux soon, but for what I've already seen, I'm feeling that I'll end with a solution where I'll have everything in a big global state repository, where I'll have to be creative to segregate states for each component (a BEM scheme for IDs??). Seems like chaos – Roberto Giordano Barra May 05 '23 at 18:09
  • I like the solution of create an object using React.useState for each component, and always pass this state for the component. We will end up with an state object for each component. Maybe there's a way in this direction. I'll try something like that in my study time. – Roberto Giordano Barra May 05 '23 at 18:13
1

I believe here the best way will be to pass a reference to children you need to have an access to their DOM elements and grabbing properties from them (e.g. their width) Here are some materials that can help you understand that better:

https://react.dev/learn/referencing-values-with-refs

https://www.altogic.com/blog/difference-between-controlled-and-uncontrolled-component

How to add "refs" dynamically with react hooks?

Please, write a comment if smth is unclear and I'll edit the answer to be more specific if needed