Pass props not a child component (ReactJS) - reactjs

How pass props to component which is not a child component
//I want pass mainData to Component2
let mainData = [
{
text_plain: "Text1",
},
{
text_plain: "Text2",
},
];
function Component1 (props) {
return (
<div>
<Link to={`Component2 url`}>
</div>
)
}
I don't want to make the Сomponent2 a child, because i don't want rendering Component2 in Component1. How to solve this problem?

For this you are going to want a global state management system. There are many out there, but I prefer context.
Context is a react hook and the documentation can be found here:
https://reactjs.org/docs/hooks-reference.html#usecontext

Related

Is it possible to pass data to components without a parent?

I understand that the normal way is to pass props through a parent, but I want to know how else I can pass props to a component.
let C1 = createReactClass({
...
render: function() {
console.log('render C1');
return (
<div>
<button onClick={this.cambiaAAzul}>Azul</button>
<button onClick={this.cambiaAVerde}>Verde</button>
<button onClick={this.cambiaARojo}>Rojo</button>
<p>Estado C2 <strong style={ {color: this.state.color} }>{this.state.color}</strong></p>
<C2 color={this.state.color}/> // It is common
</div>
);
}
});
Typically, to solve the props-drilling problem, which is what seems to be the issue you are trying to solve, the useContext hook should help.
So set up a context,
const C1ContextProvider = ({children}) => {
//...
// the Provider gives access to the context to its children
return (
< C1Context.Provider value={someValue}>
{children}
</C1Context.Provider >
);
}
... and then in your component where you need someValue, you can just do this:
import React, { useContext } from "react";
import { C1Context } from "../C1Context";
//...
const values = useContext(AirDCPPSocketContext);
cons foo = values.someValue; // <-- someValue obtained from the context
//..
I don't know how it is possible to not have parents but you can pass informations by local storage and context hooks.
Props are by definition arguments passed into a React component. Since React components are instantiated in the context of their parent, I'm not sure if it would be possible to pass props in any other way.
There are many other ways to get data in React though. You could query data from an API or other source, or you could pull from a state manager (such as redux). It just depends on what you are trying to accomplish.
Props are simply things passed into a component when it's called.
For instance:
C1.js
function C1((prop1, prop2) {
<h1>{prop1} {prop2}</h1>
})
App.js
<C1 prop1="Hello" prop2="World" />
<C1 prop1="React's" prop2="Great" />
By referencing the C1 component in App.js, you can call it with different props to produce different results.
Now I'm not too familiar with the createReactClass and render: you're using, as this is a style of React I've never learned. However, I'd guess that props provide the same function.
Your question asks about props without a parent. Well. Props without a parent wouldn't be props, they'd just be normal JS data types inside your file.
Hope this helps :)
The component's local state only can drill into child components. for passing props without using React component's local state. you have to use state management libraries like Context API or Redux
These libraries are created to make you able to pass props into nonrelated or sibling components
Example with redux:
Here I Assume that you set up redux in your project. imagine you have two components that you want to pass props without parent-child relation.
const changeMyWeightAction = (weight) => {
return {
type: 'CHANGE_MY_WEIGHT',
payload: weight
}
}
const JenniferFunctionComponent = () => {
const dispatch = useDispatch()
return (
<div>
<span>hello I'm Jennifer and I can decide my weight</span>
<input onChange={e => dispatch(changeMyWeightAction(e.target.value)})/>
</div>
)
}
const WeightFunctionComponent = () => {
const weight = useSelector(state => state.Jenny.weight)
return (
<span>Jenny's weight is {weight}</span>
)
}

Composition In React with params

I am trying to create an architecture that in some way imitates the slots from VUE.
The idea is for the parent component to be able to inject some props into the component and the child can inject the rest of the props.
This is how I tried to approach this problem, unfortunately this approach will not work because the compontent will be "monut" every time the parent re-render takes place.
Filters = (prams) => {
useEffect(()=>{ //RENDER ALL THE TIME },[])
...
}
ParentComponent = () => <ChildComponent Filters={(props) => <Filters propA={"A"} />}
ChildComponent = (props) => {
const Filters = props.Filters;
render(<Filters probB="B" />)
}
I know, I can use useCallback for ((props) => <Filters propA={"A"} />), but only it will help only if what I want to pass to "propA" is steady.
I want to "manage" <Filters /> component in parent, so that the child does not have to handle Filters logic (props).
React gives you proper API to do most things. Using it forces you into certain paradigms that are proven to work well.
You should probably have a look at the Context and Memo APIs from React.
Or if you have to select and update state from multiple components, you might wanna have a look at libraries that provide global state, like Redux and Recoil.
Context example
// The shape
interface ContextProps {
myProp: string
}
// The context
export const MyContext = React.createContext<Partial<ContextProps>>({
myProp: 'nothing'
});
// The provider
<MyContext.Provider value={{ myProp: 'override' }}>
{children}
</MyContext.Provider>
// Consumer
const { myProp } = useContext(MyContext)
In some case you can also use useMemo or React.memo and use your own custom compare function if needed to prevent re-renders in very specific situations.

How to pass props from functional component to class component

I'm quite new to functional components and I've been on this for hours.
I simply want to pass a prop from a parent functional component to a class child component so that I will use the updated prop (which will be a boolean) to change the display of an element. That's all.
In this scenario, I want to switch the sidenav from opened to closed based on the prop.
Here is the parent component (functional):
let opened = false;
function openSidenav(){
opened = !opened;
}
const [sidebarOpened, setOpened ] = useState(opened);
return (
<Sidebar sidebarOpened={opened} />
)
and the child component (class):
componentDidUpdate(prevProps) {
if(this.props.sidebarOpened !== prevProps){
this.setState({ sidebar: true});
}
}
It's just not working, the child component isn't receiving changes, I guess I didn't pass the prop rightly. I know the code just needs correction but I don't know where I'm not getting it.
Thank you.
The argument to useState is only used once. You need to set the state in openSidenav function to trigger a re-render.
Parent
function openSidenav(){
setOpened(prev => !prev);
}
const [sidebarOpened, setOpened ] = useState(false);
return (
<Sidebar sidebarOpened={sidebarOpened} />
)
Also in child component, use prevProps.sidebarOpened (not just prevProps).
Child
componentDidUpdate(prevProps) {
if(this.props.sidebarOpened !== prevProps.sidebarOpened){ //<---- see here
this.setState({ sidebar: this.props.sidebarOpened});//<---- see here
}
}
p.s - Also, since you are using props directly in child component, you can consider to not to copy props into state.
In parent,
const [sidebarOpened, setOpened ] = useState(false);
function openSidenav(){
setOpened(!sidebarOpened);
}
return (
<Sidebar sidebarOpened={sidebarOpened} />
)
And in child component class directly use this.props.sidebarOpened instead of copying over the prop to state. If you intend to edit the value of sidebarOpened in the child component, pass setOpened to the child component as a prop and use that to edit the value.

How to mock data with props in your React Functional Component

In my React application, i am developing a screen using Functional Component.
I want to populate the data on the screen with mock data until my API is ready. I basically have an Accordion with open state where i want to display the names. Right now, i am hardcoding name to populate that. Later, i will be replacing with the actual data coming from Store. So to do that i am defining the hard coded data like below in my component itself as after the API is ready, my props will have all the required data.
function MyComponent (props) {
props={
history: {},
data:[
{
name:’XYZ’,
},
{
name:’ABC’,
}
]
}
return (
<div>Content goes here </div>
)
}
This throws me error. I want to understand if i am doing this correctly as i need to read the data values inside my div.
Props are immutable, so you should not change them.
Instead, you could mock the props that you are passing to MyComponent
Example:
In the parent component:
function MyApp() {
const mockProps={
history: {},
data:[
name:’XYZ’,
]
}
return <MyComponent {...mockProps}/>
}
and in MyComponent
function MyComponent (props) {
// do something with props here
return <div>Content goes here </div>
}
It is probably best to mock this data as coming from parent container, that way when you add Redux library later, you can simply change /where/ props are being sent from.
e.g
in Parent JS:
const Parent = props => {
const [accordionData, setData] = useState(['#1', '#2', '#3'])
/ ... rest of component /
return <Accordion accordionData={accordionData} />
}
in
const Accordion = props => {
const { accordionData } = props // pull props from parent component.
const mapAccordionData = accordionData.map(el => { return <div key={el}>el</div> })
return mapAccordionData
}
Something like this should work.
ParentJS is feeding the accordion an array of data via parent->child props. Later this will be store->child props. Accordion (child) is then rendering that data to so the user can see it via divs.
You would pass props into a component. They should come from either a parent's component state or a store (like Redux store).
function MyComponent(props) {
return <div>{props.hello}</div>;
}
class ParentComponent extends React.Component {
state = {
hello: 'Hello World!',
}
render() {
return <MyComponent hello={this.state.hello} />;
}
}
You can also pass a function that changes the state of the parent making the props also change for MyComponent. It won't mutate them but rather return a new state and therefore pass a new set of props.
Let me know if you need any further explanation.

GraphQL HOC messes with ref to children | React

I am using React and Apollo for my project.
I got this in my component MenuModal:
onClick = () => {
console.log(this.child)
this.child.onSubmit(); // do stuff
};
render() {
return (
<Modal.Content scrolling>
<MenuEdit
ref={ref => (this.child = ref)} // Using ref to access it's properties
selectedValues={selectedValues}
match={match}
menu={menu}
/>
My component MenuEdit has a function defined in class:
onSubmit = values => {
console.log('calling inner form submit', values);
if (this.child) {
this.child.submitFromOutside();
}
};
I should be able to call onSubmit from MenuModal right?
But I am currently getting this:
And when I console.log this.child in my onClick function I can see this:
So there's no onSubmit function there. When seeing GraphQL I wondered if it had something to do with me exporting the component with the graphQL HOC.
export default compose(
graphql(UPDATE_MENU, { name: 'updateMenu' }),
withApollo,
withRouter
)(MenuEdit);
And when I changed it just to:
export default MenuEdit;
I can see my function
So I wonder how I write my export so I still can access my function in my child. Thanks.
The HOC wrapps your component into another component. You can see this in the React devtools. You will see that the component renders a component around your wrapped component. Something like this
<Apollo(ChildComponent)>
<ChildComponent />
</Apollo>
Your ref then points to the Apollo(ChildComponen) element instance.
What you are doing here looks like an antipattern to me. In React we usually don't call functions on rendered elements (except sometimes DOM elements). The idea is rather that children call functions of their parents by receiving them as properties. The best thing in your case is to get rid of the reference and move your state and actions up the component chain. Alternatively you can use the new render prop style in react-apollo.
There was a contribution to the Apollo repository to address this issue...
https://github.com/apollographql/react-apollo/pull/410
Wrapping your component export like this withApollo(Component, { withRef: true }) will expose your child methods. Accessible using ref.current.wrappedInstance.

Resources