React pass props from parent wrapper to child - javascript

I need to pass props from wrapper to child component
Have a structure like this:
CabinetBlockContainer.jsx
smallChild.jsx
Right now my smallChild.jsx looks like:
return (
<CabinetBlockContainer>
<div className={props.className}>
<Typography variant="h6" color="primary">
{props.title}
</Typography>
<Typography variant="caption">{props.subtitle}</Typography>
</div>
<BalanceSmallBlock balance="1254.51" needIcon={props.needIcon} />
</CabinetBlockContainer>
);
and my container looks like:
return (
<div className={props.className}>
<div className="block-wrapper" >
</div>
</div>
);
})
I have many styles for my blocks, that's why I created wrapper(CabinetBlockContainer). I need to pass props from my CabinetBlockContainer to its child component. I don't really know is it the best practice, but seems normal.
I have tried to find in documentation how to pass props like this, but have any solution.

Use {props.children} inside your wrapper, it seems you want to do something like this.

You can pass props to a children while cloning it with new props
for better understanding how props and state work please refer this
and here is an example of previously answered same question on SO

Related

Best way to change CSS in multiple components of the same component in React

I have a component that i'm using 3 times with different data which I am able to complete with the following code;
<div>
<Container className="mt-5">
<Row>
{author_data.map((authors) => {
return (
<Col key={authors.id} className="pe-5 ps-5">
<Author
key={authors.id}
image={authors.image}
author={authors.author}
description={authors.description}
handleClick={(author) => setAuthor(author)}
/>
</Col>
);
})}
</Row>
</Container>
</div>
);
However Im looking to change the CSS on each component once I click on one of the Author components. something like the below using native JS.
document.getElementById("author1").classList.add("addGrayScale");
document.getElementById("author2").classList.add("addGrayScale");
document.getElementById("author3").classList.remove("addGrayScale");
I have used the useState and useContext hooks but I can't seem to get it to work because the Author component will receive the same props. Should I create separate components for each Author? or is there another way to do this.

Set props on react class

I'm using a third party component.
I have two classes named Parent and Child. In Parent component I use that third party component which accepts a class name as a prop and renders in itself.
So the parent component looks like this:
render(){
return (
<div className="section">
<Select
placeholder={placeholder}
valueComponent={Child}
/>
</div>
);
What I want to do is to pass some props to Child component, but I've always done this like <Child someProp="prop"/>.
Is there any way to pass props to Child component in this manner?
I don't know if the Select library provides a way to do that. In case, you could always use a wrapper component:
// Create a child wrapper component and pass it to Select.
function ChildWrapper(props) {
return <Child {...props} someProp="prop" />;
}
render(){
return (
<div className="section">
<Select
placeholder={placeholder}
valueComponent={ChildWrapper}
/>
</div>
);
}

How to efficiently pass the same "prop" to every stateless presentation component?

I have what looks like it will be a simple and common case of non-DRY code - I'm hoping there's a way to avoid this.
I have a page to render information about an object based on a route like this:
<Route path="project/:projectid" component={ProjectDetails}/>
So... the 'project id' comes in as a prop from React Router, and every stateless presentation component needs the resulting project object:
class ProjectDetails = ({project}) => {
render() {
return (
<div className="project-details-page container-fluid">
<HomeLeftBar/>
<div className="col-md-10">
<ProjectHeaderBar project={project}/>
</div>
<div className="project-centre-pane col-md-7">
<ProjectActions project={project}/>
<ProjectDescription project={project}/>
<ProjectVariations project={project}/>
</div>
<div className="project-right-bar col-md-3">
<ProjectContacts project={project}/>
<ProjectCosting project={project}/>
</div>
</div>
)
}
}
export default connect(
state => ({project: state.projects[state.router.params.projectid]})
)(ProjectDetails)
How should I clean this up, so I don't have to pass the project to every component?
I've noted a couple of similar questions this and this at least. But while their titles are similar, their details are not. They seem to ask more advanced questions about more specific situations.
For me, passing the data down from the top via props is the clearest way to get data into your leaf components, so I think what you've done here is fine.
The bit that looks not-clean is that you're passing the whole project object to every component but at a glance, it looks as though each of those components is responsible for rendering only a portion of that project object.
Passing only the branches of project that each component needs will make the relationship between the data and the view much clearer.
<ProjectContacts project={project.contracts}/>
<ProjectCosting project={project.costing}/>
and in turn I think this will make the whole component feel cleaner:
class ProjectDetails = ({project: { costings, description, variations, title, actions, contacts} }) => {
render() {
return (
<div className="project-details-page container-fluid">
<HomeLeftBar/>
<div className="col-md-10">
<ProjectHeaderBar title={title}/>
</div>
<div className="project-centre-pane col-md-7">
<ProjectActions actions={actions}/>
<ProjectDescription description={description}/>
<ProjectVariations variations={variations}/>
</div>
<div className="project-right-bar col-md-3">
<ProjectContacts contacts={contacts}/>
<ProjectCosting costings={costings}/>
</div>
</div>
)
}
}
I assume you are using react-router. You can do something like this:
<Router history={history}>
<Route path="project/:projectId">
<Route path="participants" component={Participants} />
<Route path="progress" component={Progress}/>
</Route>
</Router>
All children of <Route path="project/:projectId"> have this.props.params.projectId available. For example, url to the Participants component is "project/:projectId/participants", and therefore projectId is a param when rendering Participants.
Also, if the project details should be rendered the same way on all pages, you can add a component on the Route to "project/:projectId", which is responsible for doing rendering the project details. (That component would receive Participants or Progress as this.props.children, which you'd have to render in the new component.)

How to avoid extra wrapping <div> in React?

Today I have started learning ReactJS and after an hour faced with the problem..
I want to insert a component which has two rows inside a div on the page.A simplified example of what I am doing below.
I have an html:
<html>
..
<div id="component-placeholder"></div>
..
</html>
Render function like this:
...
render: function() {
return(
<div className="DeadSimpleComponent">
<div className="DeadSimpleComponent__time">10:23:12</div >
<div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
</div>
)
}
....
And below I am calling render:
ReactDOM.render(<DeadSimpleComponent/>, document.getElementById('component-placeholder'));
Generated HTML looks like this:
<html>
..
<div id="component-placeholder">
<div class="DeadSimpleComponent">
<div class="DeadSimpleComponent__time">10:23:12</div>
<div class="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
</div>
</div>
..
</html>
The problem that I am not a very happy that React forcing me to wrap all in a div "DeadSimpleComponent". What is the best and simple workaround for it, without explicit DOM manipulations?
UPDATE 7/28/2017: Maintainers of React added that possibility in React 16 Beta 1
Since React 16.2, you can do this:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
This requirement was removed in React version (16.0), so now you are able to avoid that wrapper.
You can use React.Fragment to render a list of elements without creating a parent node, official example:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
More here: Fragments
Update 2017-12-05:
React v16.2.0 now fully supports rendering of fragments with improved support for returning multiple children from a components render method without specifying keys in children:
render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}
If you are using a React version prior to v16.2.0, it is also possible to use <React.Fragment>...</React.Fragment> instead:
render() {
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
}
Original:
React v16.0 introduced returning an array of elements in render method without wrapping it in a div: https://reactjs.org/blog/2017/09/26/react-v16.0.html
render() {
// No need to wrap list items in an extra element!
return [
// Don't forget the keys :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
At the moment, a key is required for each element to avoid the key warning but this could be changed in future releases:
In the future, we’ll likely add a special fragment syntax to JSX that
doesn’t require keys.
You can use:
render(){
return (
<React.Fragment>
<div>Some data</div>
<div>Som other data</div>
</React.Fragment>
)
}
For further details refer to this documentation.
Use [], instead of ()'s to wrap the entire return.
render: function() {
return[
<div className="DeadSimpleComponent__time">10:23:12</div >
<div className="DeadSimpleComponent__date">MONDAY, 2 MARCH 2015</div>
]
}
I created a component to wrap child components without a DIV. It's called a shadow wrapper: https://www.npmjs.com/package/react-shadow-wrapper
This is still required, BUT React now make sure to create elements without creating an additional DOM element.
The extra wrapping needed (normally with a parent div) because Reacts createElement method require a type parameter which is either a tag name string (such as 'div' or 'span'), a React component type (a class or a function). But this was before they introduce React Fragment.
Refer this NEW api doc for createElement
React.createElement : Create and return a new React element of the given type. The type argument can be either a tag name string (such as 'div' or 'span'), a React component type (a class or a function), or a React fragment type.
here is the official example, Refer React.Fragment.
render() {
return (
<React.Fragment>
Some text.
<h2>A heading</h2>
</React.Fragment>
);
}
I know this question has been answered, you can of course use React.Fragment which doesn't create a node but let's you group stuff like a div.
Additionally if you want to have fun you can implement (and learn lots of things) a React mode that removes the extra div's and for this I really want to share a great video on how you can do it on the react code base itself.
https://www.youtube.com/watch?v=aS41Y_eyNrU
This is of course not something that you would do in practice but it's a good learning opportunity.
You won't be able to get rid of that div element. React.render() needs to return one valid DOM node.
Here is one way to render "transculent" components:
import React from 'react'
const Show = (props) => {
if (props.if || false) {
return (<React.Fragment>{props.children}</React.Fragment>)
}
return '';
};
----
<Show if={yomama.so.biq}>
<img src="https://yomama.so.biq">
<h3>Yoamama</h3>
<Show>
There is workaround too. The below block code generates fragment without the need of React.Fragment.
return [1,2,3].map(i=>{
if(i===1) return <div key={i}>First item</div>
if(i===2) return <div key={i}>Second item</div>
return <div key={i}>Third item</div>
})

How to customize nested components?

How to customize nested components?
I'm building React Native app with Redux.
I have three screens in my app that render list of users.
Follower/Following should show FollowButton:
<FollowersContainer>
<UserList onFollow={func} onUnfollow={func} users={[...]}>
<UserCard user={user} onFollow={func} onUnfollow={func}>
<FollowButton onFollow={func} onUnfollow={func} isFollowing={bool} userId={string} />
</UserCard>
</UserList>
</FollowersContainer>
Ask question screen should show AskButton:
<AskQuestionContainer>
<UserList onAsk={func} users={[...]}>
<UserCard user={user} onAsk={func}>
<AskButton onPress={onAsk} />
</UserCard>
</UserList>
</AskQuestionContainer>
Search Results should not show any button
<SearchResultsContainer>
<UserList users={[...]}>
<UserCard user={user} />
</UserList>
</SearchResultsContainer>
As you can see, all three screens uses UserList and UserCard components.
Currently UserList and UserCard needs to know about onFollow onUnfollow and onAsk actions and how to pass them around.
This can get complicated and not very flexible.
Ideally I want to do something like:
<UserList
rowComponent={
<UserCard button={<FollowButton />} />
}
/>
But how do I pass the actions from the top level component into the actual button? and How do I know which actions to pass?
I could use connect on the actual buttons to pass them the actions directly but I prefer these components stay pure and flexible.
Any suggestion on how to solve it in a clean way?
Thanks,
Ran.
You can pass components as a prop.
render() {
var passedButton = (<FollowButtton />);
var row = (<UserCard button={passedButton} />);
return (
<UserList rowComponent={row}/>
);
};

Categories

Resources