Pass two children as props to a React component - javascript

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}/>

Related

Optimal way to set state of another component from

there's a few posts explaining how to update state from another component but I'm still unable to parse the solution for my particular problem. I want the submit button in my SideBar.js component to trigger nextProblem() in my tableA.js component when it is clicked. This will cause the state of tableA.js to change as problemNum goes from 1 to 2, generating a different form. I can't import SideBar.js component into my tableA.js due to my design layout though! SideBar.js also contains images. Any ideas?
I'm using a CSS grid for the layout of my page:
grid-template-areas:
"navbar navbar navbar navbar"
"sidebar tableA ... ..."
"sidebar tableA ... ..."
"sidebar tableA ... ..."
I'm using App.js to route to the pages:
function App() {
return (
<Router>
<div className="App">
<Routes>
<Route path={"/"} exact element={<MainPage/>}/>
<Route path={"/gamePage"} exact element={<GamePage/>}/>
</Routes>
</div>
</Router>
);
}
export default App;
I created a SideBar.js component that contains a logo at the top and a submit button at the bottom:
class SideBar extends Component {
componentDidMount() {
}
render() {
return (
<div className={"sidebar"}>
<div className={"logo_group"}>
<img className={"some_logo"} src={logo}/>
</div>
<div className={"nav_group"}>
<button className={"home"}/>
<button className={"about"}/>
</div>
<img className={"an_image"} src={someImage}/>
<div className={"button_group"}>
<button className={"submit_button"} onClick={() => nextProblem()}>Submit</button>
</div>
</div>
)
}
}
export default SideBar
and a tableA.js component with a function nextProblem() that changes the state of the component:
class tableA extends Component {
state = {
problemNum: 1,
problemStatus: 'unsolved',
userAnswer: []
};
nextProblem = () => {
this.setState(state => ({
problemNum: state.problemNum + 1,
}))
}
componentDidMount() {}
render() {
return (
<div>
<form>
...depends on the state of the problem number
</form>
</div>
)
}
export default tableA
I then consolidate everything in GamePage.js:
const GamePage= () => {
return (
<div className={"gamepage-container"}>
<div className={"navbar"}>
<NavBar></NavBar>
</div>
<div className={"sidebar"}>
<SideBar></SideBar>
</div>
<div className={"tableA"}>
<TableA></TableA>
</div>
...
</div>
)
}
export default GamePage
i'd propably go the approach of letting the gamepage handle the state and such and send down the problem and the update function down the components as props. Depending on how big this thing will grow you could also use a centralized store.
const GamePage= () => {
const [problem, setPropblem] = useState(0)
return (
<div className={"gamepage-container"}>
<div className={"navbar"}>
<NavBar></NavBar>
</div>
<div className={"sidebar"}>
<SideBar
onSetNext={() => setProblem(problem + 1)}
></SideBar>
</div>
<div className={"tableA"}>
<TableA
problem={problem}
></TableA>
</div>
...
</div>
)
}
export default GamePage
and in your sidebar the button becomes
<button className={"submit_button"} onClick={() => this.props.onSetNext()}>Submit</button>
similarly you access the props.propblem instead of state in your table.

Can I share data between sibling components in this case?

Is there a way to share data between sibling components without the need to return the component from which I need the data? here is an example to explain it better:
import React from "react";
import "./App.css";
function App() {
return (
<div className="App">
<header className="App-header">
<div>
<h1>Home page</h1>
<Component1 />
<Component2 />
</div>
</header>
</div>
);
}
const Component1 = (props) => {
const importantInfo = "secret-info";
if (props.handleInfo) {
props.handleInfo(importantInfo);
}
return (
<div>
<p>I am component number 1</p>
</div>
);
};
const Component2 = () => {
const handleInfo = (info) => {
console.log(info);
};
return (
<div>
<p>I am component number 2</p>
<Component1 handleInfo={(info) => handleInfo(info)} />
</div>
);
};
export default App;
I want to use some data from Component1 in Component2. The only way I found to do this, was to return the component1 inside the component2 and put the props in there.
I mean this:
return (
<div>
<p>I am component number 2</p>
<Component1 handleInfo={(info) => handleInfo(info)} />
</div>
Is there a way not to return the component and still receive the data throw props? I know I can do it with UseContext and with other methods, but I want to know if I can do it with props. Thanks!
What you can do is creating a new state in App.js as the following:
function App() {
const [commonInfo, setCommonInfo] = useState('information')
return // rest of the code
}
Then pass that down through props in both components as:
return (
<div className="App">
<header className="App-header">
<div>
<h1>Home page</h1>
<Component1 commonInfo={commonInfo} setCommonInfo={setCommonInfo} />
<Component2 commonInfo={commonInfo} setCommonInfo={setCommonInfo} />
</div>
</header>
</div>
);
Thus you can destructure from props in the components as the following:
// and also in Component2
const Component1 = (props) => {
const { commonInfo, setCommonInfo } = props
// rest
}

How to give React parent component access to children state without form (with Sandbox)?

I'm currently looking for a way to access children state from a parent component that will handle API calls for the whole page.
The actual problem is the following:
Parent is the parent component that will render two Child components.
Each of the Child has a state that it is responsible for.
The "Kind of Submit Button" will have a "Kind of Submmit Action" (this is all quoted because this is not a form) and that should fire the function to provide access to the children state. Is there a way (some React feature) to do this without using <form> or without creating an intermediate parent component to hold all the state? I want each children to be responsible for its own state.
Code Sandbox with example of the code below
import React, { useState, useRef } from "react";
function ChildOne() {
const [childOneState, setChildOneState] = useState(false);
return (
<React.Fragment>
<h3>Child One</h3>
<p>My state is: {childOneState.toString()}</p>
<button onClick={() => setChildOneState(true)}>Change my state</button>
</React.Fragment>
);
}
function ChildTwo() {
const [childTwoState, setChildTwoState] = useState(false);
return (
<React.Fragment>
<h3>Child Two</h3>
<p>My state is: {childTwoState.toString()}</p>
<button onClick={() => setChildTwoState(true)}>Change my state</button>
</React.Fragment>
);
}
function Button(props) {
return (
<button onClick={props.kindOfSubmitAction}>Kind of Submit Button</button>
);
}
function Parent() {
const childOneState = useRef("i have no idea");
const childTwoState = useRef("ihave no idea");
function kindOfSubmitAction() {
console.log("This is the kindOfSubmit function!");
// This function would somehow get
// access to the children state and store them into the refs
return;
}
return (
<React.Fragment>
<h1>Iam Parent</h1>
<div>
<b>Child one state is: </b>
{childOneState.current}
</div>
<div>
<b>Child two state is: </b>
{childTwoState.current}{" "}
</div>
<Button kindOfSubmitAction={kindOfSubmitAction} />
<ChildOne />
<ChildTwo />
</React.Fragment>
);
}
export default Parent;
When several components need access to the same data, it's time for Lifting State Up.

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>
);

when to use this.props.children and why

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>
)
}
}

Categories

Resources