skip to Main Content

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

Answers


  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>
    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search