Passing down React Components dynamically through props? - reactjs

I'm looking for a solution. I have a Sidebar component that needs to render a different component based on which button in the parent component is pressed. I'm unsure of the best way to approach this problem, or if its possible. Heres my React code:
Parent Component
The content prop on the Sidebar component needs to pass down different components based on which Button components are clicked (so the first Button would pass a component in the content prop, and the second would pass down a component etc).
return (
<Fragment>
<Sidebar
isOpen={this.state.menuOpen}
content={<Filters />}
/>
<PanelWrapper>
<IconContainer>
<Button />
<Button />
</IconContainer>
</PanelWrapper>
</Fragment>
)
Child Component
And here that content prop would be rendered:
class Sidebar extends Component {
render() {
return (
<Menu
customBurgerIcon={ false }
noOverlay
isOpen={this.props.isOpen}
>
{this.props.content}
</Menu>
)
}
}
Thank you

Rather than passing a component as props, I'd probably do it something like this
class Sidebar extends Component {
render() {
return (
<Menu
customBurgerIcon={ false }
noOverlay
isOpen={this.props.isOpen}
>
{switch(this.props.content) {
case("type1"): <mycomponent1 />
...
}}
</Menu>
)
}
}

Related

ReactJS, React-Router: Calling parent function

I am working on a React App, trying to call a parent method from a child component, some code of the parent component below:
class NavigationBar extends Component {
constructor(props){
super(props);
this.state={isLoggedIn: false};
}
updateLoginState(){
alert("Login from NavigationBar");
}
GetBar() {
//const isLoggedIn = this.props.isLoggedIn;
if (false){ //isLoggedIn
return this.UserNavBar();
}
return this.StrangerNavBar();
}
StrangerNavBar(){
return (
<div>
<HashRouter>
<div>
{/* ... */}
<div className="content">
<Route exact path="/LoginCC" loginUpdate={this.updateLoginState} component={LoginCC} />
</div>
</div>
</HashRouter>
</div>
);
}
render() {
return (
this.GetBar()
);
}
}
export default NavigationBar;
This component is supposed to redirect the user to different content pages based on whether or not he is logged in, using a Router. If a button is clicked in LoginCC.js the method updateLoginState should be invoked which just displays a message for now. The child content page LoginCC.js looks as follows:
class LoginCC extends Component {
constructor(props){
super(props);
this.state = {isLoggedIn: false};
}
render() {
return (
<div>
<HashRouter>
{/* ... */}
<Button variant="primary" size="lg" block onClick={this.props.loginUpdate}>
Log in
</Button>
{/* ... */}
</HashRouter>
</div>
);
}
}
export default LoginCC;
I passed the method reference as a prop to LoginCC when rendering this component using the Router, so a message should pop up if I press the button, but nothing happens.
Am I passing the prop incorrectly or something else I've missed? I'm new to React so any help is appreciated.
Route doesn't pass any custom props to components. You should use other method to pass functions.
One of solutions is:
<Route exact path="/LoginCC" render={
props => <LoginCC {...props} loginUpdate={this.updateLoginState}/>
} />
Note that updateLoginState will not get this when called. You should either bind it or declare it as an arrow function to get the correct this.
Also check the Context documentation.

how can I dynamically attach sidebar components to multiple instances of sidebar?

I'm new to React and building out a design a ran into a problem.
I have a component called SideBar. I am using this component two times, one on each side of the page.
The problem is that I would like to add different components to each instance of the SideBar component. These would be lists of various items and etc. I assumed I could next component tags but the sidebar component doesn't output.
import React, { Component } from "react";
import SideBar from "./WorkspaceComponents/SideBar";
import ScrollerBox from "./WorkspaceComponents/SideBarComponents/ScrollerBox";
class Workspace extends Component {
render() {
return (
<main className="reely-workspace">
<SideBar position="SideBarLeft">
<ScrollerBox />
</SideBar>
<SideBar position="SideBarRight" />
</main>
);
}
}
export default Workspace;
Your sidebar component should receive a children prop and render it out.
Something like this:
class Sidebar extends Component {
render() {
const {children} = this.props;
return (
<div className="sidebar">
<h1>Sidebar</h1>
{children}
</div>
)
}
}
Check out this post on react docs to understand how to compose react components: https://reactjs.org/docs/composition-vs-inheritance.html
You can make your SideBar Component a wrapper component which wraps around the content given in it.
Making SideBar Component a Wrapper Component :
class Sidebar extends Component {
render() {
return (
<div className="sidebar">
// You can add any custom element here //
{this.props.children}
</div>
)
}
}
All your element passed inside the SideBar Component will now be rendered as a part of SideBar along with what it contains.
Way to consume the wrapper component:
<SideBar>
<Content1></Content1>
<Content2></Content2>
<Content3></Content3>
</SideBar>

How to add different child components to component

I'm new to react. I'm trying to create the following structure for a component in react:
<Sidebar>
<Box>
<Title/>
<Item/>
<Item/>
</Box>
<Box>
<Title/>
<Switch/>
</Box>
</Sidebar>
I can include the Title component in the Box component and pass each title value through props. How do I include the Item component in just the first Box component and not the second?
Is the best way to pass the Item and Switch components into the Box components as props?
There are quite a few ways to do what you're asking and really it really depends on where you are going with your program.
Multiple Types of Box components (with different names)
Wrap all of you sub-components in a div, and pass that div to your Box's 'children' prop. (Slightly changes your hierarchy).
Example
<Box children={<div><Title/><Item/><Item/></div>}/>
<Box children={<div><Title/><Item/></div>}/>
Hierarchy
<Sidebar>
<Box>
<div>
<Title/>
<Item/>
<Item/>
</div>
</Box>
<Box>
<div>
<Title/>
<Switch/>
</div>
</Box>
</Sidebar>
More fancy, build your sub-components from an array or other JS object that you pass as a prop and have a function inside 'Box' that reads that array and builds your sub components.
Leverage the special children prop in order to render arbitrary children:
children is a default prop passed implicitly to every component
this children prop is automatically populated with any elements contained within the parent component
instead of using props.children you can destructure props and use ({ children(, ...otherProps) }) instead
In action:
Box.js
const Box = ({ children }) => (
<div className='box'>
{children}
</div>
)
Sidebar.js
const Sidebar = ({ children }) => (
<div className='sidebar'>
{children}
</div>
)
App.js
import React from 'react'
import Sidebar from './path/to/Sidebar'
import Box from './path/to/Box'
class App extends React.Component {
constructor() {
super()
// state or whatever
}
render() {
return (
<Sidebar>
<Box>
{/*
Anything you put in here (other components
included) will be automatically rendered
*/}
</Box>
<Box>
{/* Same here */}
</Box>
</Sidebar>
)
}
}

How to give different backgrounds to the same component?

Edited:
I am new to react, and so far couldn't find the answer to this question. I have a <Box /> component, which renders some HTML.
import React, { Component } from 'react'
class Box extends Component {
render() {
return (
<div className="box-wrapper">
<div className="different-image-for-different-copies">
</div>
<div className="box-name">
Golden Lion
</div>
</div>
)
}
}
export default Box
On one page, I have three copies of the same component. I want to be able to give unique background-image to the inner with the className different-image-for-different-copies in each of those three components without making a new component.
Component <Box /> is the child of a component <Wrapper />. What I want exactly is to be able to change the background of a certain <div> located in the child <Box /> component from the parent <Wrapper /> component. For example:
class Wrapper extends React.Component {
render() {
return (
<div>
<Box "some way to change the background of the inner div" />
</div>
)
}
}
What would be the best way to do this?
Pass you image as a props to your Box component. Then in your component, set its style like this:
<div style={{ backgroundImage: `url(${this.props.imageUrlFromProps})`}}>
</div>
That's a basic example but should help you get your image to show up.
Use a prop to pass to the component which background image it should use and set it on your component using inline style. If the set of images is limited, the rendering could instead pick a CSS class to apply.

Using React, is it possible to define a component inside the definition of another component?

(this question differs to 'is it possible to use a component inside another', this question is 'can I define a component inside the definition of another', it is not a duplicate of 'Can I write Component inside Component in React?')
Is it possible to define a component inside the definition of another component? This way I can use the props of the outside component in the inner component. It would keep the code more concise. Something like the following...
class AComponent extends Component {
CustomButton = (props) => {
let { disabled, ...otherProps } = props // <-- props of the inner component
const {isDisabled, currentClassName} = this.props // <-- props of the main component
return (
<button
className={className}
disabled={isDisabled}
{...otherProps}>
</button>
)
}
render() {
return (
<div>
<CustomButton>Add something</CustomButton>
<CustomButton>Delete something</CustomButton>
<CustomButton>Edit</CustomButton>
</div>
)
}
}
If the custom button was defined on its own (the usual way of defining components) I would have to do something like below which is ok but more verbose and less dry as I repeat the definition of {...buttonProps} for each component
let buttonProps = {
className: this.props.currentClassName,
disabled: this.props.disabled
}
return (
<div>
<button {...buttonProps}>Add something</button>
<button {...buttonProps}>Delete something</button>
<button {...buttonProps}>Edit</button>
</div>
)
While yes, it's possible to define one function component inside another function component, this is not recommended.
Referring to the ReactJs docs:
reactjs.org/docs/components-and-props
reactjs.org/docs/conditional-rendering
Most, if not all, examples show child components being defined outside of the parent component.
Defining a component inside another will cause the child component to be re-created on mount and unmount of the parent, which could cause unexpected behavior if the child is using props from the parent, and cannot handle if those props are suddenly undefined.
It's best to define components separately.
Yes! I needed to define the function component in the render method...which makes sense
class AComponent extends Component {
render() {
const ButtonLocal = (props) => {
const {isDisabled, currentClassName} = this.props
return (
<Button
disabled={isDisabled}
className={currentClassName}
{...buttonProps}>
</Button>
)
}
return (
<div>
<ButtonLocal>Add something</ButtonLocal>
<ButtonLocal>Delete something</ButtonLocal>
<ButtonLocal>Edit</ButtonLocal>
</div>
)
}
}
Very much possible to add components inside a parent component. Consider following example:
<ParentComponent style={styles}>
<ChildComponent style={styles} {...props} />
</ParentComponent>

Resources