when to use this.props.children and why - javascript

I'm reading this file https://github.com/luispcosta/reddit_clone/blob/master/client/components/Main.jsx
and I don't get line 37, where does the this.props.children come from? I know you can pass props like
<Component name='alan'/>
and you can get name by doing this.props.name to get alan. But this props.children means?

In JSX expressions that contain both an opening tag and a closing tag,
the content between those tags is passed as a special prop:
props.children. There are several different ways to pass children:
https://facebook.github.io/react/docs/jsx-in-depth.html#children-in-jsx
For example:
<Main>
<p>This is a child element</p>
<button>So is this</button>
</Main>
this.props.children in Main will be an array of elements.
// Main.jsx
render() {
return <div>
{this.props.children}
</div>;
}
Would render
<div>
<p>This is a child element</p>
<button>So is this</button>
</div>

In react an element in JSX is represented as
const elem = (<div id="test"> Hi I am a div. </div>);
And there is another alternative way to represent the react element.
So similar element can be represented as -
var elem = React.createElement(
"div",
{ id: "test" },
" Hi I am a div. "
);
createElement has following signature :
React.createElement(component, props, ...children)
Above ...children means any nested JSX elements inside div.
Nested elements in itself can be another react-element and may be more than one of them.
const elem = (<div id="test"> <h1> Hi I am a div. </h1> </div>);
What is props.children?
The returned elem contains light weight object representation.
It has a field called props set. This props field contains custom attributes passed and reference to nested elements i.e child elements.
Now lets see how it is represented
const elem = (<div id="test">Hi I am a div.</div>);
console.dir(elem);
const elem1 = (<div id="test"> <h1> Hi I am a div. </h1> </div>);
console.dir(elem1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
From the logs we can see that props has a property called children. So each parent element contains immediate reference to its children.
"props": {
"id": "test",
"children": "Hi I am a div."
}
When can I use props.children?
When ever you want to get access to children elements in code.
There can be scenario like you want to get access to all of your nested elements.
A simplest example-
You have created a custom button like below -
class MyButton extends React.Component {
render() {
return <button> {this.props.children} </button>;
}
};
// What ever you pass insede <MyButton> and </MyButton>
// You can access it inside your MyButton component via {this.props.children}
const elem = (<MyButton> test1 </MyButton>);
ReactDOM.render(
elem,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root">
</div>
Another scenario could be you want to loop over your nested children and may be passing some other extra props or may just accessing them -
class MyButton extends React.Component {
render() {
return (
<button onClick={this.props.handleClick}>
{this.props.children}
</button>
);
}
};
class ButtonContainer extends React.Component {
handleClick = () => {
console.log("Clicked");
}
render() {
const childrenWithProps = React.Children.map(this.props.children,
(child) => {
return React.cloneElement(child, { handleClick: this.handleClick });
});
return (
<div>
{childrenWithProps}
</div>
);
}
};
const elem = (
<ButtonContainer>
<MyButton> test1 </MyButton>
<MyButton> test2 </MyButton>
<MyButton> test3 </MyButton>
</ButtonContainer>
);
ReactDOM.render(
elem,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root">
</div>
There are other scenarios as well with react-router e.g when route changes you want to get access to your children elements to render them on screen.
I have included working code and example where ever possible. I hope this helps you.

It is simple. I will explain by an example
Lets say you have created some component called ComponentDemo.
It is used like this:
<ComponentDemo>
// This component can receive some HTML tags here that will be passed as children props for example:
<div> Hello world</div>
</ComponentDemo>
Then,inside ComponentDemo render function you can use it as:
render(){
// lets use the HTML tags we passed as children here
{this.props.children}
}
what will happen?
ComponentDemo will render
<div> Hello world</div>
which is the value passed by props.children

You can check the API reference of react-router
So, it is just the api provided by react-router which is imported in https://github.com/luispcosta/reddit_clone/blob/master/client/routes.js.
const routes = (
<Route path="/" component={App}>
<Route path="groups" component={Groups} />
<Route path="users" component={Users} />
</Route>
)
class App extends React.Component {
render () {
return (
<div>
{/* this will be either <Users> or <Groups> */}
{this.props.children}
</div>
)
}
}

Related

Adding a prop to a specific React element type in any level of the DOM tree

I'm trying to add a "position" prop to the 'Child' components and use it inside the 'Parent' component, So the only purpose of the 'PositionWrapper' is to add one prop and return the new children.
The problem is that when I call props.children inside 'Parent' I get a 'PositionWrapper' component instead of 'Child' components as I want.
I know that I can call props.children.props.children and I will get the 'Child' components but this solution doesn't look like a dynamic one (What if I remove the 'PositionWrraper'? Or what if add more wrappers?)
Does anyone know an optimal/ a better solution?
(or Am I implementing the 'PositionWraaper' correctly? )
Thanks!
The code:
Child.js:
const Child = (props) => {
return (
<>
<p>my id is :{ props.id}</p>
<p>my position is : {props.position} </p>
</>
)
}
export default Child;
PositionWrapper.js :
import React from "react"
const PositionWrapper = (props) => {
return (
React.Children.toArray(props.children).map((child)=> React.cloneElement(child, { position: [0,0,0]}))
)
}
export default PositionWrapper;
Parent.js:
import React from "react";
const Parent = ( props) => {
// here I want to do things with children components of type 'Child' but props.children consists 'Wrapper' Component.
return (
props.children
)
}
export default Parent;
App.js :
import './App.css';
import PositionWrapper from './Wrapper'
import Child from './Child';
import Parent from './Parent'
function App() {
return (
<Parent>
<PositionWrapper>
<Child id ={1} />
<Child id ={2} />
</PositionWrapper>
</Parent>
);
}
export default App;
Why dont you pass position prop to Parent - since you want to use it in Parent ?
Anyway, uou should use High-Order-Component for this scenario.
Check: https://reactjs.org/docs/higher-order-components.html
You can do a complete virtual DOM tree search to pass the props only to a specific type like below. This is a simple recursive function doing depth-first traversal.
We process the children of the child and pass it as the third argument of React.cloneElement.
React.cloneElement( element, [config], [...children] )
const Child = (props) => {
return (
<React.Fragment>
<p>my id is :{props.id}</p>
<p>my position is : {props.position} </p>
</React.Fragment>
);
};
const PositionWrapper = (props) => {
return React.Children.toArray(props.children).map((child) =>
React.cloneElement(child)
);
};
const Parent = (props) => {
// here I want to do things with children components of type 'Child' but props.children consists 'Wrapper' Component.
return passPositionPropToChildren(props.children, [1, 2, 3]);
};
const passPositionPropToChildren = (children, position) => {
return React.Children.toArray(children).map((child) => {
// Process the childrens first - depth first traversal
const childrenOfChildren =
child.props && child.props.children
? passPositionPropToChildren(child.props.children, position)
: null;
return React.isValidElement(child)
? React.cloneElement(
child,
child.type.name === "Child"
? {
...child.props,
position: position
}
: child.props,
childrenOfChildren
)
: child;
});
};
function App() {
return (
<Parent>
abc
<h2>hey</h2>
<PositionWrapper>
<Child id={1} />
<Child id={2} />
<div>
<Child id={3} />
</div>
</PositionWrapper>
<Child id={4} />
</Parent>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>

Pass two children as props to a React component

I have a component like this
const Component = () => {
return (
<div>
<div className="data1">
{children}
</div>
<div className="data1">
{children2}
</div>
</div>
)
}
I would like to have Item1 and Item2 inside the "data1" div, and some other components inside the "data2" div. Writing the next code I only have Item1 and Item2 as children but I don't know how to pass the second children (for example Item3 and Item4)
<Component>
<Item1/>
<Item2/>
</Component>
I have to reuse the Component multiple times into the app so a function called children2 that returns the elements is not a good idea because they are different depending on where I use the component.
The recommended way is to create custom props for each child:
const App = () => <Component child1={<Item1 />} child2={<Item2 />} />
const Component = ({child1, child2}) => {
return (
<div>
<div className="data1">
{child1}
</div>
<div className="data1">
{child2}
</div>
</div>
)
}
const Item1 = () => <p>Item 1</p>
const Item2 = () => <p>Item 2</p>
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I've made an StackBlitz in order for you to check a simple solution to render multiple Children been pass to a component. But to resume my solution, if you do this:
<Component>
<Item1/>
<Item2/>
</Component>
You could in Component.js (or wherever the Component is defined) map (this.props.children.map({})) the prop children in order to get the details of every child past to the <Component />.
You can pass multiple components as follows:
import React from 'react'
function Child (props) {
return (<>
<div>{props.child1}</div>
<div>{props.child2}</div>
</>
)
}
export default Child
import React from 'react'
function Parent {
return (
<>
<Child
children1={<Item1/>}
children2={<Item2/>}
/>
</>
)
}
export default Parent
till me if it work
const Component = (item1,item2) => {
return (
<div>
<div className="data1">
{item1}
</div>
<div className="data1">
{item2}
</div>
</div>
)
}
how to used it
which item one what you want to add as item like this <item1/>
<Component item1={item1} item2={item2}/>

JSX syntax arrow function inside render

I just saw this code in this other question and i don't understand how it works :
let Parent = () => (
<ApiSubscribe>
{api => <Child api={api} />}
</ApiSubscribe>
)
I understand something like this:
let Parent = ({api}) => (
<ApiSubscribe>
<Child api={api} />
</ApiSubscribe>
)
but never saw {foo => <Bar bar={bar} />} in render before,
can someone help me understand this?
A component can access the child elements given to it with the children prop. If a function is given as child, the component can call this function. The component calling the children function can then call the function with any argument it sees fit.
Example
const Child = props => {
return props.children('test');
};
const Parent = () => (
<Child>
{function(arg1) {
return <div> This is a {arg1} </div>;
}}
</Child>
);
ReactDOM.render(<Parent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

react higher order component

Im looking into higher order functions and i dont really understand how this part works.
say i have the following function:
const withAdminWarning = WrappedComponent => {
return props => (
<div>
{props.isAdmin && <p>This is private info. Please dont share!</p>}
<WrappedComponent {...props} />
</div>
);
};
const Info = props => (
<div>
<h1>Info</h1>
<p>This info is: {props.info}</p>
</div>
);
const AdminInfo = withAdminWarning(Info);
ReactDOM.render(
<AdminInfo isAdmin={true} info="There are the details" />,
document.getElementById("app")
);
From my understanding of components, to access the props variable, you have to use either props, if its a stateless component, or this.props if it is a class component.
From where does the props come into play in the example above as i cant get access to it from the WrappedComponent or anywhere else apart from the return statement.
The Higher order Component returns a function which is a functional component. Am I right in thinking that foo(Info) means withAdminWarning(Info)?
So after calling withAdminInfo the AdminInfo Component looks basically like:
const AdminInfo = props => (
<div>
{props.isAdmin && <p>This is private info. Please dont share!</p>}
<div>
<h1>Info</h1>
<p>This info is: {props.info}</p>
</div>
</div>
);

React interract with dom

How can I 'talk' with dom elements with react?
For example - I need to bind some actions with some js lib
Both approaches returns undefined for some reason
componentDidMount() {
const element1 = document.querySelector('.home-container')
const element2 = ReactDOM.findDOMNode(this);
// returns undefined, undefined
console.log(element1.length, element2.length);
}
render() {
return (
<div className="home-container">
...
</div>
)
}
But console.log(element1) returns html from render itself though
How can I work with them?
And what correct lifecycle method for this?
You use "refs":
<div ref={e => {this.div = el}} ...>...</div>
Once your component has rendered, with the above, its div property (you can use any name you want) will refer to the div element that was rendered.
Here's an example largely copied from the link above that focuses a text input when it's rendered:
class AutoFocusTextInput extends React.Component {
componentDidMount() {
this.textInput.focus();
}
render() {
return (
<input type="text"
ref={(input) => { this.textInput = input; }} />
);
}
}
ReactDOM.render(
<AutoFocusTextInput />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Categories

Resources