Can I pass extra props to a child component?

Viewed 38
  1. <ComponentA> is supposed to render <ComponentB> (not import it but rather render it as a child)
  2. <ComponentB> comes with its own props (propsForComponentB)
  3. But I want <ComponentA> to pass one extra prop of its own to <ComponentB>

I'm thinking of something like the below, but being new to React I don't know if/how it's possible:

  <ComponentA>
    <ComponentB {...propsForComponentB} />
  </ComponentA>
//component-a.jsx

export default function(props) {

  function doSomething(dataFromChildComponent){
     ...
  }

  return(
    {
      /* 
        Here I want to render the children components while passing an extra prop
        to each of them. My syntax is obviously wrong. This is mostly pseudocode to get 
        my point across. Is this possible in some way ? 
      */ 
      props.children.map((child) => {child componentAmethod={doSomething}  }) 
    }
  )
}
//component-b.jsx

export default function(props) {
  /*
     here `props` should contain all of the original
     `propsForComponentB` passed to ComponentB initially, 
      plus the extra prop `componentAmethod`
  */
  function onSomething(){
     props.componentAmethod(...arguments)
  }

  .....
  ...
}

To give you an example, with Ember.js you can do cool stuff like the below, out of the box:

  <ComponentA as |doSomething|>
    <ComponentB onSomething={doSomething}/>
  </ComponentA>

doSomething is an internal method of <ComponentA> that is made available to whatever children are rendered inside <ComponentA>

1 Answers

The useImperativeHandle is likely what you are after here. It allows you to pass a ref around and then assign information to it.

In the sample below you can see we click a button in ComponentB which triggers the console.log function in ComponentA.

The docs recommend to use this pattern sparingly. So perhaps have a think about a different structure of your code that might help avoid using refs if not necessary.

export default function App() {
  const inputRef = useRef();

  return (
    <>
      <span>App Title</span>
      <br />
      <ComponentA inputRef={inputRef}>
        <ComponentB inputRef={inputRef} />
      </ComponentA>
    </>
  );
}

export const ComponentA = (props) => {
  const specialFunction = (msg) => {
    console.log(msg);
  };

  // Component A attaches the function
  useImperativeHandle(props.inputRef, () => ({
    specialFunction
  }));

  return (
    <>
      <span>Component A stuff</span>
      <br />
      {props.children}
    </>
  );
};

export const ComponentB = (props) => {
  const handleClick = () => {
    props.inputRef.current.specialFunction("hello");
  };

  return <button onClick={handleClick}>Print Hello</button>;
};

Here it is in a sandbox, check the console as you click: https://codesandbox.io/s/bold-firefly-p8uhtn?file=/src/App.js

Related