How to pass React Component as props to another component - javascript

I am trying to call PopupDialog.tsx inside Content.tsx as a sibling of Item.tsx.
Previously PopupDialog.tsx is called inside C.tsx file but due to z index issue i am trying to bring it out and call it in Content.tsx
Is it possible to somehow pass the whole component(popupDialog and its parameters) in Content.tsx so that i could avoid passing back and forth the parameters needed for popupdialog in content.tsx.
Code in C.tsx where PopupDialog component is called.
const C = (props: Props) => (
<>
{props.additionalInfo ? (
<div className="infoButton">
<PopupDialog // need to take this code out and want to add in Content.tsx
icon="info"
callback={props.callback}
position={Position.Right}
>
<div className="popuplist">{props.additionalInfo}</div>
</PopupDialog>
</div>
) : (
<Button className="iconbutton"/>
)}
</>
);
Content.tsx where i would like to call PopupDialog.tsx with its parameters
const Content = (props: Props) => {
const [componentToRender, docomponentToRender] = React.useState(null);
const [isAnimDone, doAnim] = React.useState(false);
return (
<div className="ContentItems">
<PWheel agent={props.agent} />
{isAnimDone && (
<>
<Item {props.agent} />
{componentToRender &&
<PopupDialog/> //want to call here with all its parameters to be passed
}
</>
)}
</div>
);
};
Folder Structure
App.tsx
->ViewPort.tsx
->Content.tsx
->PWheel.tsx
->Item.tsx
->A.tsx
->B.tsx
->C.tsx
{props.additionalinfo &&
->PopupDialog.tsx
->PopupDialog.tsx

So if I understand the question correctly you want to pass one component into another so that you can use the properties or data of the passed componenet in your current component.
So there are three ways to achieve this.
1)Sending the data or entire component as prop.This brings disadvantage that even though components which don't require knowledge
about the passed component will also have to ask as a prop.So this is bascially prop drilling.
2)The other is you can use context api.So context api is a way to maintain global state variale.so if you follow this approach you don't need to pass data or componenet as props.Wherever you need the data you can inport context object and use it in componenet.
3)Using Redux library.This is similar to context api but only disadavantage is that we will have to write lot of code to implement this.Redux is a javascript library.
Let me know if you need more info.

You need to :
<>
<Item {props.agent} />
{componentToRender &&
<PopupDialog abc={componentToRender} /> //you must call in this component, in this case i name it is abc , i pass componentToRender state to it
}
</>
and then PopupDialog will receive componentToRender as abc, in PopupDialog , you just need to call props.abc and done .
If you need to know more about prop and component you can see it here

I think what you want to use is Higher-Order-Components (HOC).
The basic usage is:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
Below is such an implementation that takes a component (with all its props) as a parameter:
import React, { Component } from "react";
const Content = WrappedComponent => {
return class Content extends Component {
render() {
return (
<>
{/* Your Content component comes here */}
<WrappedComponent {...this.props} />
</>
);
}
};
};
export default Content;
Here is the link for higher-order-components on React docs: https://reactjs.org/docs/higher-order-components.html

Make use of
useContext()
Follow this for details:
React Use Context Hook

Related

Is there a way to generalize a component to have the props/onclick function without adding the same thing for others component

I use React + styled and my question is about the following code
<MobileButton
onClick={props.handleMobileDropdownElementClicked}
padding={isSmallDevice ? 1 : 0}
>
Name
</MobileButton>
Is there a way to generalise this component to write like this without having props and onclick()? like the following code.
<MobileButton>
Name
</MobileButton>
I was just curious if there is things in react or styled component that could do that if we are repeating the same component with the same props/onclick function.
Thank you
Sure, you can make a new component that doesn't require said props. But you'll still have to pass the props when creating that component initially.
For example:
const YourComponent = (props) => {
const NewMobileButton = (newProps) => {
return (
<MobileButton
onClick={props.handleMobileDropdownElementClicked}
padding={isSmallDevice ? 1 : 0}
>
{newProps.children}
</MobileButton>
)
}
return (
<>
<NewMobileButton>1</NewMobileButton>
<NewMobileButton>2</NewMobileButton>
</>
)
}

How to import a component that is rendered in another component?

I have a form component rendered in a component, component1, and I want to use it in another component, component2, but I want to use it with all the functionality that it has inside component1. How can I do this? I tried exporting it from inside component1 but it didn't work.
Here is where the form component is rendered in component1:
return (
<OutsideClickHandler onOutsideClick={this.handleBlur}>
//some not important code was here
<div
id={id}
className={popupClasses}
ref={node => {
this.filterContent = node;
}}
style={contentStyle}
>
{this.state.isOpen ? (
<FilterForm // this FilterFrom I want to export into another component
id={`${id}.form`}
paddingClasses={popupSizeClasses}
showAsPopup
contentPlacementOffset={contentPlacementOffset}
initialValues={initialValues}
keepDirtyOnReinitialize={keepDirtyOnReinitialize}
onSubmit={this.handleSubmit}
onChange={this.handleChange}
onCancel={this.handleCancel}
onClear={this.handleClear}
>
{children}
</FilterForm>
) : null}
</div>
</div>
</OutsideClickHandler>
);
}
}
Here is where I want to import and use the form component:
return (
<div className={classes}>
//some not important code was here
<ModalInMobile
id="SearchFiltersMobile.filters"
isModalOpenOnMobile={this.state.isFiltersOpenOnMobile}
onClose={this.cancelFilters}
showAsModalMaxWidth={showAsModalMaxWidth}
onManageDisableScrolling={onManageDisableScrolling}
containerClassName={css.modalContainer}
closeButtonMessage={modalCloseButtonMessage}
>
//here I want to import and use the *form component*
</ModalInMobile>
</div>
);
FilterForm job is to perform certain logics and display some elements in the DOM, based on its props and states (Just like how system works, you can have a car parked or have a car running both are the same system but with different inputs and states). So you already have your component. If you mean that attributes like popupSizeClasses, contentPlacementOffset, keepDirtyOnReinitialize, .... are shared between component1 and component2, you can make a wrapper around FilterForm with those values passed to FilterForm. So you would render FilterFormWrapper component instead.
But make sure that some props like onCancel (which is equal to this.handleCancel) are independent and does not have any dependency (state or props) to component1, so you can extract them.

Spread operator to pass all other props to a component. React.js

I'm having trouble understanding the spread operator when I want to pass all other props to a component.
Any help would be appreciated.
import React, { Fragment } from "react";
import SiteCard from "./SiteCard";
const SiteList = ({ sites }) => {
return (
<Fragment>
{sites.map((site) => {
return (
<SiteCard
key={site.login.uuid}
image={site.picture.large}
firstName={site.name.first}
lastName={site.name.last}
city={site.location.city}
country={site.location.country}
sensors={site.dob.age}
otherSiteProps={...site} // how can I pass the site props here?
/>
);
})}
</Fragment>
);
};
export default SiteList;
You are almost there with the solution.
You need to pass it as otherSiteProps={{...site}}.
This is if you want to pass site as an object to otherSiteProps property of SiteCard.
If you want to spread site and have multiple props for component SiteCard you do it like this:
<SiteCard
key={site.login.uuid}
image={site.picture.large}
firstName={site.name.first}
lastName={site.name.last}
city={site.location.city}
country={site.location.country}
sensors={site.dob.age}
{...sites}
/>
This in case that sites is an object. If site is an array, this wont work.
You just need to write:
<SiteCard
key={site.login.uuid}
image={site.picture.large}
firstName={site.name.first}
lastName={site.name.last}
city={site.location.city}
country={site.location.country}
sensors={site.dob.age}
{...site} // how can I pass the site props here?
/>
But wait, why you're making so complicated? You can just use:
<SiteCard {...site} />
Now, in your SiteCard component use required props.
And if I were you, I would not have separated SiteCard component for this scenario. I would just write:
{sites.map((site) => {
return (
// everything here I will utilize in html.
);
})}

How to access ref that was set in render

Hi I have some sort of the following code:
class First extends Component {
constructor(props){super(props)}
myfunction = () => { this.card //do stuff}
render() {
return(
<Component ref={ref => (this.card = ref)} />
)}
}
Why is it not possible for me to access the card in myfunction. Its telling me that it is undefined. I tried it with setting a this.card = React.createRef(); in the constructor but that didn't work either.
You are almost there, it is very likely that your child Component is not using a forwardRef, hence the error (from the React docs). ref (in a similar manner to key) is not directly accesible by default:
const MyComponent = React.forwardRef((props, ref) => (
<button ref={ref}>
{props.children}
</button>
));
// ☝️ now you can do <MyComponent ref={this.card} />
ref is, in the end, a DOMNode and should be treated as such, it can only reference an HTML node that will be rendered. You will see it as innerRef in some older libraries, which also works without the need for forwardRef in case it confuses you:
const MyComponent = ({ innerRef, children }) => (
<button ref={innerRef}>
{children}
</button>
));
// ☝️ now you can do <MyComponent innerRef={this.card} />
Lastly, if it's a component created by you, you will need to make sure you are passing the ref through forwardRef (or the innerRef) equivalent. If you are using a third-party component, you can test if it uses either ref or innerRef. If it doesn't, wrapping it around a div, although not ideal, may suffice (but it will not always work):
render() {
return (
<div ref={this.card}>
<MyComponent />
</div>
);
}
Now, a bit of explanation on refs and the lifecycle methods, which may help you understand the context better.
Render does not guarantee that refs have been set:
This is kind of a chicken-and-egg problem: you want the component to do something with the ref that points to a node, but React hasn't created the node itself. So what can we do?
There are two options:
1) If you need to pass the ref to render something else, check first if it's valid:
render() {
return (
<>
<MyComponent ref={this.card} />
{ this.card.current && <OtherComponent target={this.card.current} />
</>
);
}
2) If you are looking to do some sort of side-effect, componentDidMount will guarantee that the ref is set:
componentDidMount() {
if (this.card.current) {
console.log(this.card.current.classList);
}
}
Hope this makes it more clear!
Try this <Component ref={this.card} />

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

Categories

Resources