Pass data from grandchild to parent in React - javascript

Hello i have an array called info[] in a grandchild component and i want my parent component when a button is clicked to access the array. I also want a sibling component to have access to it. How is this possible .. i am a bit confused.
Should I use use-context ?
Thank you!

If I have understand what you are asking it could be something like this.
const GrandChild = ({ setParentInfo }) => {
const info = [1, 2, 3];
const handleClick = () => {
setParentInfo(info);
};
return <button onClick={handleClick}>Set parent info</button>;
};
const Sibling = ({ parentInfo }) => {
return <div>{parentInfo.length}</div>; // Do whatever you need with parentInfo
};
const Parent = () => {
const [parentInfo, setParentInfo] = useState([]);
return (
<div>
<GrandChild setParentInfo={setParentInfo} />
<Sibling parentInfo={parentInfo} />
</div>
);
};
Here you don't need context because you don't have that much layers but if you need to drill down the props than use a context.

If you want to share state among many different components in your application, and you believe that passing State as a prop is "a very long journey" to move around I'm probably you should consider something like use context hook.
Either way what you just described seems like a simple use case witch will not need context.
What you should do is:
On the parent you have [state, setState]
On the current component pass setStat as a prop to child component and then from child component pass setState as a prop to grandchild component.
Then on grandchild component you can do something like:
props.setState(array).
So now on the parent component the variable state will have been updated with the value array from the grandchild component.
If you want to pass state to siblings component, and by sibling I assume you mean sibling of the parent,
Then you should move the state from parent one level up let's say the parent of the parent.. and do what I've described above.
So create useState high in your component tree,
And pass State and setState as well to children as props, setState will be passed as function, so you can call it on the grandchild component or any other component

Related

Why does props in props.functionName only need to be called sometimes?

In react, specifically referencing the hooks/functional paradigm, when do you need to use props.functionName? As far as I can tell, if the functions are named the same, you can omit props as follows:
Parent.js
...
<Child functionName={functionName}/>
...
Child.js
...
functionName();
...
However, if the name changes, props must be referenced as follows:
Parent.js
...
<Child otherName={functionName}/>
...
Child.js
...
props.otherName();
...
Am I correct? If so, why use the second design pattern? (Perhaps just to call out that the function comes from a parent and isn't defined at the child level. Or maybe some other reason?)
No. The name you use depends entirely on how the child component processes the props it is passed. How the parent component determines what value to pass is completely irrelevant.
If the props are placed in a variable named props then you need to access them through the object stored in the variable.
const Child = (props) => {
props.functionName();
...
}
If the first argument is destructured, then each property is stored in its own variable.
const Child = ({functionName}) => {
functionName();
...
}
If the value is copied to another variable inside the component then you can also use the variable it was copied to.
const Child = (props) => {
const functionName = props.functionName();
functionName();
...
}
False, It is Destructuring Props in React;
Destructuring is a convenient way of extracting multiple values from data stored in (possibly nested) objects and Arrays
props is an object so we can use the Destructuring
Destructuring gives access to the use of props in a more readable format and discards the need for props for every property.
<Child functionName={functionName} name={name}/>;
const child = (props)=>{
// you need to write props.functionName
props.functionName();
const thisName = props.name
};
const child =({functionName,name})=>{
// you dont need to write *props.*
functionName();
const thisName = name
};
When interfacing with a child component, the name that you use for something in your parent component may be different from the prop that the child component requires.
Just for example, say that your parent component has something to do with school, and you have:
const [studentId, setStudentId] = useState();
const [parentId, setParentId] = useState();
But you also have a child component for students that expects an id prop. Then, to pass down the studentId to it, you'd do:
<Student id={studentId} />
And in that child component, you'd reference it by doing props.id.
You wouldn't want to do
const [id, setId] = useState();
in the parent component, and then
<Student id={id} />
when passing it down because then it wouldn't be clear in the parent component which ID that stateful value referred to - you'd probably have to add a comment.
If so, why use the second design pattern?
Sometimes, like in the situation I just described, the child component isn't designed with all identifiers used in the parent component in mind - which is perfectly reasonable, that's what allows for so many things in programming to be modular (and adaptable and useful). As a result, sometimes you need a prop or variable to have one name in the parent component, and another in the child component, which requires the
<Child otherName={functionName}/>
approach.

Accessing state in a parent component from a child component

I'm currently accessing the state of a parent component in a child component through the use of callbacks, but I'm not quite sure how it works:
export default function parentComponent({ type }) {
const
[inEditMode, setInEditMode] = useState(false)
return (
<>
<div className={containerCssClasses}>
<childComponent onCancel={() => { setInEditMode(false); }} type={type} />
here, the parent component is calling the child component and passing an anonymous function to the component for it to call back.
In the child component:
function childComponent({onCancel}) {
return (
<div>
<Button onClick={() => onCancel()} variant="link" >
</div?
);
}
I am a bit confused how this is able to work properly if the child component doesn't have access to setInEditMode(). I understand that when passing a function to another function (in this case, a component), it is passed by reference. But does that necessarily mean all of the variables within that function are passed by reference as well? I am new to react (and javascript), but when I looked this concept up I couldn't find a good explanation.
Your implementation is the right way to go. More than callbacks these functions you pass down to child components are call props and I invite you to read the documentation about them.
https://reactjs.org/docs/components-and-props.html
You can also find very detailed articles about it:
https://itnext.io/what-is-props-and-how-to-use-it-in-react-da307f500da0
Whatever you'll pass from the parent to the child can be used in the child component as if it was called in the parent one.
In your case the child is indeed gonna trigger setInEditMode(false)
As you're not passing any variable to it you can actually call it as such:
<Button onClick={onCancel} variant="link" >
The parent component's state you pass to child component as props is not updated as parent's state is changed. so, you need a callback function to access parent's current state at any given time. Also, if you have dependent state value in parent and child component or rather multiple components, you can move it to reducer if you're using redux for state management.

How to transfer state between React components with hooks?

With React classes when you have state in the constructor you could inherit it to the child component directly and from the child to the parent using callbacks. How can you transfer state from parent to child with hooks? Is the only way useReducer or Redux?
The concepts of passing props down to child or conveying information from child to parent hasn't changed with the arrival of hooks.
Hooks provide, you a way to use lifecycle like functionality and states with functional components.
you can declare your state in parent with useState and pass it down as props to child component as you would normally have done with class components or functional components previously
For example:
const Parent =() => {
const [count, setCount] = useState(0);
return <Child count={count} setCount={setCount} />
}
const Child = ({count, setCount}) => {
const updateCount = () => {
setCount(prev=> prev + 1);
}
return (
<div>
<div>Count: {count}</div>
<button type="button" onClick={updateCount}>Increment</button>
</div>
}
You can refer this post for more details on lifecycles with hooks:
ReactJS lifecycle method inside a function Component
Please refer the react docs with hooks FAQs
Classes and functional components (or func-comp as my mate calls them) are the same in respect to props.
You can pass props from parent to child in a functional component just like how you'd do with a class.
//Parent
const Parent = () => {
const [state, setState] = React.useState({ products: 1, isAvailable: true})
const addProduct = (data) => {
// Your function
}
return (
<Child product info={state} addProduct={addProduct} />
)
}
export default Parent
And in the child component you can receive the props typically the way you would will classes.
const Child = ({productInfo, addProduct}) => {
// Do what ever you like with the props
}
Cheers!
Perhaps, you should ask yourself why you would like to use inheritance. It seems like for many cases where many developers tend to immediately think about using OOP-style inheritance, React.js might recommend composition instead (see https://reactjs.org/docs/composition-vs-inheritance.html).
With functional components, composition is probably the only choice, which means that your "parent" component would render the "child" component, passing whatever state it needs to pass via the child's props.
Whether your project needs Redux or not should be completely orthogonal to the composition-vs-inheritance question.

Set a child array state object from props value

I am creating a react application using hooks but I'm getting a weird behavior on my code, I'm not going to put all my code here but I will give you an example what it's going on.
const Child = props => {
const {data} = props;
const [myData, setMyData] = useState(data);
const items => myData.map( r => <li> r </li> );
return ( <ul> { items } </ul> );
}
const Parent = () => {
return (<div>
<Child data={ [1, 2, 3] }
</div> );
}
I am making changes to the array that the Parent component sends to the Child component.
When I add a new element to the array, the Child component re-render so MyData is equals to the array ( this makes sense because the Child components is re-render by the props change ).
If I delete an element from the array the Child component is re-render but myData doesn't change and the element I deleted from the array is still there in myData.
Why the useState sets the array to myData when I add elements to the array but when I delete elements it seems like this doesn't work,even though the Child component is re-render.
I know it seems a little dumb, you can ask me, why you don't just use the props value on the Child component instead of a state value, well the idea is on the Child component there is a search control so I can make some kind of searching over MyData and not over the props value ( but maybe there is another way ).
I think the issue is how you're using props.
When Child renders, it gets props.data from Parent. It then copies data to its component state as the variable myData.
From here on, changes to props can trigger the Child to re-render, but myData won't be redefined again via useState. That happens only once.
If you're writing code that does hot-reloading (you save the file and the application reloads in the browser), it might seem like changing the props sent to Child updates myData, but that's not happening in a production environment.
My suggestion: if you're going to fork props into the state of Child, think of props as an initial value, and not something that Parent can update.
The React docs explain why this is an anti-pattern:
The problem is that it’s both unnecessary (you can use this.props.color directly instead), and creates bugs (updates to the color prop won’t be reflected in the state).
Only use this pattern if you intentionally want to ignore prop updates.
React constructor docs
useEffect(() => {
setMyData(data)
},[data])
your data will be load to state only once. but you can handle changes on data by parent component with useEffect, useEffect will updates when data will updated
there is full code
const Child = props => {
const {data} = props;
const [myData, setMyData] = useState(data);
useEffect(() => {
setMyData(data)
},[data])
const items => myData.map( r => <li> r </li> );
return ( <ul> { items } </ul> );
}
const Parent = () => {
return (<div>
<Child data={ [1, 2, 3] }
</div> );
}
you can read about React use effect

How to update child state first and than parent's state

In short :-
I want to update child state first and than update parent state but react batches setSate and calls parent setState first and than childs. For more understanding read the explanation written below.
Basically i have a parent component which is having two child.
Sort component :- This component opens a dropdown for sort options selection. on click it should update the local state and than call the function passed as props from parent.
Product collection :- This component shows the products based on the sort selected.
I am passing a function (handleClick) from parent component to sort to get the value of selected sort into the parent and than passing it to product collection.
Since sort is a dropdown i want to close it first as soon as user selects a option and than i want to update the parent.
Right now i am using it in such a way, first updating local state and in callback calling the function passed from parent.
handleClick(param) {
this.setState({ selectedType: param.slug }, () =>
this.props.onHandleSort(param.slug)
)
}
But as written in React docs it batches the process and calls the parent setState first and than the child.
For example, that if both Parent and Child call setState
during a click event, Child isn’t re-rendered twice. Instead, React
“flushes” the state updates at the end of the browser event. This
results in significant performance improvements in larger apps.
I need it to happen in such way only because i need my dropdown to close first and than the parent should update.
I have tried the following this but nothing seems to work.
Made sort component stateless and dependent on the props from the parent but this will take time to close the dropdown.
Used callback of setState but since as written in docs it batches and calls parent setState first and than childs.
Judging from your codepen, you should lift the withRouter-wrapper up to the parent, let it figure out the selectedType and pass it to your sort component. In your onHandleSort, you can then set the new query.
class Parent extends Component {
// ...
handleClick (slug) => {
this.props.router.push({ query: { sorting: slug } })
}
// ...
render () {
const sorting = this.props.router && this.props.router.query
? this.props.router.query.sorting
: 'RELEVANCE';
return (
// ...
<Sort value={sorting} onHandleSort={this.handleClick} />
// ...
);
}
}
export default withRouter(Parent);
export default class Sort extends Component {
// ...
handleClick (param) => {
this.props.onHandleSort(param.slug)
}
// ...
render () {
const selectedType = this.props.sorting;
return (
// ...
);
}
}

Categories