This question already has answers here:
How to pass props to {this.props.children}
(32 answers)
Closed 1 year ago.
Workaround at the bottom of the question.
I am trying to pass props down to a child component using {children}.
The Father component:
const FatherComp = ({ children, propsToPassToChild }) => (
<div>Dynamic component content:
{children}
</div>
)
The child component:
const ChildComp = ({ childProps }) => <p>This is the dynamic content</p>
Using them like so:
<FatherComp>
<ChildComp/> // childProps cannot be passed here since it's inside FatherComp
</FatherComp>
I want to pass to the ChildComp the props (propsToPassToChild ) from the FatherComp directly:
const FatherComp = ({ children, propsToPassToChild }) => (
<div>Dynamic component content:
>>>>> {children} <<<<< *passing the props somewhere here*
</div>
)
Is it possible to achive what I am trying to do with react functional components directly and without state management?
Thanks!
************ My solution ***********
So after a little while in a different project I came accross the same question and I found out a solution.
const Father = ({ child }) => {
return (
<div>
{child({ text: 'I am props from father' })}
</div>
);
};
const Child = ({ text }) => {
return (
<div>Hey there {text}</div>
);
};
and render the Father component:
const App = () => <Father child={Child} />
Just pass the child in the props of the father as a function that returns a component.
Altough it's not a 'direct' solution this solved the problem without wrapping the child with the father.
You should use render props
ref: https://reactjs.org/docs/render-props.html#gatsby-focus-wrapper
Yes, you need to do something like this:
<FatherComp>
<ChildComp name="John" age="21"/>
</FatherComp>
const FatherComp = (props) => (
<div>Dynamic component content:
{props.children}
</div>
)
Accept props in the FatherComp and use {props.children} to render all the children components inside of your Father component.
I'm having issues trying to get my useState variable to work. I create the state in my grandparent then pass it into my parent. Here's a simplified version of my code:
export function Grandparent(){
return(
<div>
const [selectedID, setSelectedID] = useState("0")
<Parent setSelectedID2={setSelectedID} .../> //(elipses just mean that I'm passing other params too)
<div />
)}
Parent:
const Parent = ({setSelectedID2 ...}) => {
return(
<div>
{setSelectedID2("5")} //works
<Child setSelectedID3={setSelectedID2} />
</div>
)
}
From the parent I can use 'setSelectedID2' like a function and can change the state. However, when I try to use it in the child component below I get an error stating 'setSelectedID3' is not a function. I'm pretty new to react so I'm not sure if I'm completely missing something. Why can I use the 'set' function in parent but not child when they're getting passed the same way?
Child:
const Child = ({setSelectedID3 ...}) => {
return(
<div >
{setSelectedID3("10")} //results in error
</div>
);
};
In React you make your calculations within the components/functions (it's the js part) and then what you return from them is JSX (it's the html part).
export function Grandparent(){
const [selectedID, setSelectedID] = useState("0");
return(
<div>
<Parent setSelectedID2={setSelectedID} .../> //(elipses just mean that I'm passing other params too)
<div />
)}
You can also use (but not define!) some js variables in JSX, as long as they are "renderable" by JSX (they are not Objects - look for React console warnings).
That's your React.101 :)
Here's a working example with everything you have listed here. Props are passed and the function is called in each.
You don't need to name your props 1,2,3.., they are scoped to the function so it's fine if they are the same.
I moved useState and function calls above the return statement, because that's where that logic should go in a component. The jsx is only used for logic dealing with your display/output.
https://codesandbox.io/s/stupefied-tree-uiqw5?file=/src/App.js
Also, I created a working example with a onClick since that's what you will be doing.
https://codesandbox.io/s/compassionate-violet-dt897?file=/src/App.js
import React, { useState } from "react";
export default function App() {
return <Grandparent />;
}
const Grandparent = () => {
const [selectedID, setSelectedID] = useState("0");
return (
<div>
{selectedID}
<Parent setSelectedID={setSelectedID} selectedID={selectedID} />
</div>
);
};
const Parent = ({ selectedID, setSelectedID }) => {
setSelectedID("5");
return (
<div>
{selectedID}
<Child setSelectedID={setSelectedID} selectedID={selectedID} />
</div>
);
};
const Child = ({ selectedID, setSelectedID }) => {
setSelectedID("10");
return <div>{selectedID}</div>;
};
output
10
10
10
const [selectedID, setSelectedID] = useState("0")
should be outside return
In my App component, I have 2 components Navbar and View. In my Navbar component, I have an ExportButton component which onClick should generate a screenshot of the View component by passing its ref.
App.js
function App() {
const view = useRef();
return (
<div className="App">
<Navbar takeSnap={view}/>
<View ref={view}/>
</div>
);
}
Navbar.js
const Navbar = ({ takeSnap }) => {
return (
<>
<Lists />
<ExportButton takeSnap={takeSnap} />
</>
);
};
Button.js
const ExportButton = ({ takeSnap }) => {
function handleClick(takeSnap) {
domtoimage.toBlob(takeSnap.current, {}).then(function (blob) {
saveAs(blob, "myImage.png");
});
}
return (
<Button onClick={() => handleClick(takeSnap)} />
);
};
I having some trouble passing ref of View to use the library dom-to-image to take a screenshot. The error says "Uncaught (in promise) TypeError: Cannot read property 'cloneNode' of undefined
at makeNodeCopy". This might be a quick fix but I'm not sure where I'm going wrong.
You cannot create a ref for a component, a ref can only reference a DOM element.
When you do:
<View ref={view}/>
ref is a reserved keyword and it won't be passed down to your View render function.
You can use forwardRef to solve this problem, or simply use a different keyword such as myRef:
<View myRef={view}/>
Then when you render your View, you can assign this ref to the element you want the screenshot from:
<div ref={myRef} ...
I would like to access a ref passed between two external components using render props (real example). Can it be done?
function Component() {
// how to get access to `ref` here?
return (
<A>
{({ref}) => (
<B ref={ref}/>
)}
</A>
)
}
You may need React.forwardRef
Ref forwarding is a technique for automatically passing a ref through a component to one of its children.
This is typically not necessary for most components in the application. However, it can be useful for some kinds of components, especially in reusable component libraries.
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
Figured it out. The ref render prop is actually badly named, it's not a ref but a function to set a ref, so we can just use a inline function (thought this may cause extra renders):
function Component() {
const bRef = useRef(null);
return (
<A>
{({ref: setRef}) => (
<B ref={ref => {
bRef.current = ref;
setRef(ref);
}}/>
)}
</A>
)
}
I know you can pass all a react components props to it's child component like this:
const ParentComponent = () => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...this.props} />
</div>
)
But how do you then retrieve those props if the child component is stateless? I know if it is a class component you can just access them as this.prop.whatever, but what do you pass as the argument into the stateless component?
const ChildComponent = ({ *what goes here?* }) => (
<div>
<h1>Child Component</h1>
</div>
)
When you write
const ChildComponent = ({ someProp }) => (
<div>
<h1>Child Component {someProp}</h1>
</div>
)
From all the props that you are passing to the childComponent you are just destructuring to get only someProp. If the number of props that you want to use in ChildComponents are countable(few) amongst the total number of props that are available, destructuring is a good option as it provides better readability.
Suppose you want to access all the props in the child component then you need not use {} around the argument and then you can use it like props.someProp
const ChildComponent = (props) => (
<div>
<h1>Child Component {props.someProp}</h1>
</div>
)
Are you looking for the ES6 named argument syntax (which is merely destructuring) ?
const ChildComponent = ({ propName }) => (
<div>
<h1>Child Component</h1>
</div>
)
const ChildComponent = (props) => ( // without named arguments
<div>
<h1>Child Component</h1>
</div>
)
Optionally there is a second argument to your function depending of whether you specified a context for your component or not.
Perhaps it would be more helpful wityh a links to the docs. As stated in the first article about functional components. Whatever props passed on to the component is represented as an object passed as first argument to your functional component.
To go a little further, about the spread notation within jsx.
When you write in a component :
<Child prop1={value1} prop2={value2} />
What your component will receive is an plain object which looks like this :
{ prop1: value1, prop2: value2 }
(Note that it's not a Map, but an object with only strings as keys).
So when you're using the spread syntax with a JS object it is effectively a shortcut to this
const object = { key1: value1, key2: value2 }
<Component {...object}/>
Is equivalent to
<Component key1={value1} key2={value2} />
And actually compiles to
return React.createElement(Component, object); // second arg is props
And you can of course have the second syntax, but be careful of the order. The more specific syntax (prop=value) must come last : the more specific instruction comes last.
If you do :
<Component key={value} {...props} />
It compiles to
React.createElement(Component, _extends({ key: value }, props));
If you do (what you probably should)
<Component {...props} key={value} />
It compiles to
React.createElement(Component, _extends(props, { key: value }));
Where extends is *Object.assign (or a polyfill if not present).
To go further I would really recommend taking some time to observe the output of Babel with their online editor. This is very interesting to understand how jsx works, and more generally how you can implement es6 syntax with ES5 tools.
const ParentComponent = (props) => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...props} />
</div>
);
const ChildComponent = ({prop1, ...rest}) =>{
<div>
<h1>Child Component with prop1={prop1}</h1>
<GrandChildComponent {...rest} />
</div>
}
const GrandChildComponent = ({prop2, prop3})=> {
<div>
<h1>Grand Child Component with prop2={prop1} and prop3={prop3}</h1>
</div>
}
You can use Spread Attributes reducing code bloat. This comes in the form of {'somearg':123, ...props} or {...this.props}, with the former allowing you to set some fields, while the latter is a complete copy. Here's an example with ParentClass.js :
import React from 'react';
import SomeComponent from '../components/SomeComponent.js';
export default class ParentClass extends React.Component {
render() {
<SomeComponent
{...this.props}
/>
}
}
If I do, <ParentClass getCallBackFunc={() => this.getCallBackFunc()} />, or if I do <ParentClass date={todaysdatevar} />, the props getCallBackFunc or date will be available to the SomeComponent class. This saves me an incredible amount of typing and/or copying/pasting.
Source: ReactJS.org: JSX In Depth, Specifying the React Element Type, Spread Attributes. Official POD:
If you already have props as an object, and you want to pass it in JSX, you can use ... as a “spread” operator to pass the whole props object. These two components are equivalent:
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}```
Now, let's apply this to your code sample!
const ParentComponent = (props) => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...props} />
</div>
);
I thought I would add a simple ES2015, destructuring syntax I use to pass all props from a functional parent to a functional child component.
const ParentComponent = (props) => (
<div>
<ChildComponent {...props}/>
</div>
);
Or if I have multiple objects (props of parent, plus anything else), I want passed to the child as props:
const ParentComponent = ({...props, ...objectToBeAddedToChildAsProps}) => (
<div>
<ChildComponent {...props}/>
</div>
);
This destructuring syntax is similar to the above answers, but it is how I pass props along from functional components, and I think it is really clean. I hope it helps!
But how do you then retrieve those props if the child component is stateless?
const ChildComponent = ({ *what goes here?* }) => (
<div>
<h1>Child Component</h1>
</div>
)
ChildComponent holds the name and the props will be the argument in the arrow function syntax just as you need:
const ChildComponent = props => (
<div>
<p>{props.value ? props.value : "No value."}</p>
</div>
);
If you Babel-it it will create something like this:
var ChildComponent = function ChildComponent(props) {
return React.createElement(
"div",
null,
React.createElement(
"p",
null,
props.value ? props.value : "No value."
)
);
};
For some reason, what seems to work for me is a variation on Shubham's answer above:
const ChildComponent = props => (
<div>
<h1>Child Component {props[0].someProp}</h1>
</div>
)
Using this
const ParentComponent = ({ prop1, prop2, prop3 }) => (
<div>
<h1>Parent Component</h1>
<ChildComponent {...{ prop1, prop2, prop3 }} />
</div>
);
const ChildComponent = ({ prop1, prop2, prop3 }) =>{
<div>
<h1>Child Component with prop1={prop1}</h1>
<h1>Child Component with prop2={prop2}</h1>
<h1>Child Component with prop2={prop3}</h1>
</div>
}