First question here i go... I´ve been searching and couldn´t find the best practice.
My solution (Maybe stupid):
I have a parent form that has a child select.
const [periodo, setPeriodo] = useState('0')
const cambiarPeriodo=(e)=> { setPeriodo(e) }
<NewSelect value ={periodo} onchange={(e) => { cambiarPeriodo(e) }} />
The child function component select:
const periodosChange=(e)=> {
props.onchange(e.target.value);
}
<Select value={props.value} custom name="periodo" id="periodo" onChange={periodosChange} >
Options are populated via axios database query with a useEffect.
When user selects an option in list, fires a onchange callback function and set state in parent.
Because of setState, the parent and child reloaded and cleared the user selection. The solution was to pass via prop the state to the child and assign it in value of select. <Select value={props.value}..
Is there any better way to do it, or this is a standard procedure? Actually i would like the child not to reload at all because the select list wont ever change... Tried React.memo but couldn´t make it work
There is a class-based component lifecycle's hook called shouldComponentUpdate() which you can use to prevent the child component from re-rendering if the list won't change. But this means you will have to convert your child component from a functional component to a class-based component.
The other option would be to use useMemo() and memoize the entire component as shown here.
Related
What I need to achieve is to handle a specific attribute from one JSX component that I import to its parent component in a way that I will display here.
Child component returns JSX with 'someId' attribute:
return <h1 someId={123}>{title}</h1>
And the parent assigns this JSX to a variable and then needs to read this 'someId' attribute from it - before mounting the variable to the DOM:
let mySpecialChild = <Child title="Hello boys and girls!" />
let mySpecialChildId = mySpecialChild.someId
mySpecialChild.someId is now empty. I know it looks strange and against ReactJS rules but I need this for a very specific use case (in a loop, with additional conditions related to this child attribute). Here I created a sandbox for tests:
https://codesandbox.io/s/small-wood-jx33sz?file=/src/App.js
You can work around this issue by not using JSX to render that component, but directly calling it.
Disclaimer: You should not be using this approach.
If you want the returned DOM representation directly, you will have to call the Child component as a function instead of a JSX.
So if instead of
let mySpecialChild = <Child title="Hello boys and girls!" />
you do
let mySpecialChild = Child({title:"Hello boys and girls!"}),
then you can do let mySpecialChildId = mySpecialChild.props.someId;
Updated demo at: https://codesandbox.io/s/nameless-feather-fwdhs4
You should set a state on the parent component. codesandbox
Define a state which holds the id in the parent component.
Pass the function that sets the state (setSomeId) to the child component from the parent component.
Call setState function(setSomeId) when you want.
The state of parent component will update, so it will rerender with the new value of someId.
Edit:
Notice that the state setter function you pass will not change during renders. React docs state that:
React guarantees that setState function identity is stable and won’t change on re-renders.
There other ways for doing what you want:
useImperativeHandle: If you want to read the child id imperatively, you can pass a ref to the child component from the parent component and use useImperativeHandle hook inside the child component. You can call ref.current?.getId function from the parent component. Notice that if you want to display the id in the parent component, the parent component should be rerendered. So you will see the child id when you press the button that updates the state, and rerenders the parent component. codesandbox
Ref callback: If you don't need to render the value of someId from the child component and you want to call a function whenever the child id changes, you can pass a ref callback from the parent component to the child component. The callback gets called whenever the node is changed. You can access the property you want from the callback. If you want to render someId on the screen, you have to render the parent component. So you should set its value to state. (I changed someId to data-some-id because someId is not a valid prop on a DOM element. codesandbox.
You can access props as:
CODESANDBOX LINK
let mySpecialChild = <Child title="Hello boys and girls!" />;
console.log(mySpecialChild.props.title);
when you console.log mySpecialChild then It will log as:
I would like the child component's state to update as the parent component's state updates. Any changes to parent state variables should be reflected in the child's state. How can I do this?
Thanks!
Edit:
My components are arranged in the following manner. I would like to access the parent's state from Child 2. By setting the Child 1 state to the parent's state, I will be able to do this.
Parent->Child 1->Child 2
You can pass the part of the parent state that you need as a prop to the child.
Then each time the parent state will change, the child will rerender with the correct value.
If you need to change the state from within the child, it depends on the behaviour you want.
You can make the child change the parent state by passing a callback function as a prop (you can pass the function used to change the state in the parent as a prop to the child)
Or you can make the child local state beeing reset to the parent state when it changes by listening to changes on the prop with a useEffect or ComponentDidUpdate.
useEffect(() => { setState(props.partOfparentState)},[props.partOfparentState])
or
ComponentDidUpdate(prevProps) {
if(previousProps.partOfParentState != props.partOfParentState) {
partOfParentStatethis.setState({state:props.parpartOfParentStatetOfParentState})
}
}
You could also want other behaviour which could be achieved with a more complex useEffect.
State And Props
React DOM compares the element and its children to the previous one,
and only applies the DOM updates necessary to bring the DOM to the
desired state.
the data flow in react is “unidirectional” or “top-down”,
Any state is always owned by some specific component, and any data or
UI derived from that state can only affect components “below” them in
the tree.
If you imagine a component tree as a waterfall of props, each
component’s state is like an additional water source that joins it at
an arbitrary point but also flows down.
This is why the state is often called local or encapsulated. It is not
accessible to any component other than the one that owns and sets it. #reactjs
Therefore, You Should pass the state to the child component, also known as prop.
Edit:
the hierarchy will be like this:
App(state - date) => Child1(prop date, passing the same prop to the next child) => Child2(getting date from his parent - Child1)
Example (based on Class Components):
<App>:
The root of the app.
<ClockList date={this.state.date} />
<ClockList>:
notice we are using props
<Clock date={this.props.date} />
<Clock>:
import React from "react";
const Clock = (props) => {
// Object Destructuring can also be done in the function itself.
const { date } = props;
return (
<div className="container">
<p>{date}</p>
</div>
);
};
export default Clock;
I have a problem to change state for a child from the parent component.
Here is a sample sandbox.
https://codesandbox.io/s/parent-child-communication-hooks-34tjn?file=/src/components/Child.jsx
Here is my goal: When a user clicks "Turn on all button" in the Parent component, All of the children components will be turned on together. Turn off will turn off all children.
But Still, It is necessary to control each child.
Hi and welcome to StackOverflow. I see in your CodeSandbox that you started using React Hooks. Other than the useState hook we have the useEffect which will be triggered after the dependency has changed. You can achieve that by using this hook.
Simply add a new prop to your Child Component, this prop will contain the state value for the parent, we will call this parentValue. This is your Parent Component
//Parent.jsx
//your code
{childrentdata.map(x => (
<ChildComponent
name={x.name}
buttonOn={state.ParentOn}
parentValue={state.ParentOn}
/>
))}
Then, in your Child Component add the hook
useEffect(() => {
setState(prevState => ({ ...prevState, buttonOn: props.parentValue }));
}, [props.parentValue]);
The hook will watch for props and state changes that we specify in the array dependency as the second argument. So, everytime the parent toggle changes, it will change all the children. There is a change I made, if you notice I'm using a callback inside your setState, this is the way we can get the actual value for the state without getting a stale value. So, is a good practice to use this callback to prevent side effects.
I am a beginner on React, and I am confused on how to achieve this
I have a simple function which returns a component
renderCustomButtonText(style) {
return (
<span>
<input
value={this.state.contact}
placeholder="Custom Button Text"
/>
</span>
);
}
The input value is received from the state. When loading the page for the first time it gets this value from the database so that is okay, but when updating the state again, it gets changed again.
So, basically, I want to store {this.state.contact} somewhere so that I can get the initial value of it. And NOT getting the updated store value, only the initial value which was loaded the first time.
I don't want to use Redux for such a simple use case. Any ideas?
You can't use state with functional components you need class-based component, with functional components you are limited to render props.
When you need to interact with state, or component lifecycle hooks you need to use class-based components.
React updates its component whenever you use this.setState.
If you don't want to re-render your component, I would recommend setting the information to the this-instance instead of this.state.
e.g.
this.contact = contact;
However, since you're using the value prop of input, you need to update it each time the user inputs. What you could do is setting the state in the componentWillMount method with setState.
this.setState({ contact: '...' });
Then also update the state when the user inputs by adding a onInput event to the input component.
<input
value={this.state.contact}
onInput={e => this.setState({ contact: e.target.value })}
/>
I would like to know difference between rendering component with state or props directly.
getInitialState:
data: this.props.data
Following code is for render function
1.
data = this.state.data
return (<Component data={data} />)
2.
return (<Component data={this.state.data} />)
3.
return (<Component data={this.props.data} />)
First two situations are crashing when I use setState on listening reflux action.
If anyone has recommendations to use other than setState or tell me the difference about those three code snippets would be very much appreciated.
Putting props in state like this:
getInitialState: function () {
return {
someKey: this.props.someKey
};
}
is an anti-pattern, unless you intend to modify the value of someKey later on and you use the prop as just an initial value.
So if you don't change the value of the prop passed in, you should go with number three.
The difference is that a component that doesn't have state can be considered "pure" (the same props passed in gives the same output, everytime) and those components are almost always easier to reason about. Duplicating the prop in state without mutating the state just gives you more lines of code in the component, and it might confuse someone else reading the code. It's a pure component disguised as an impure component.
A bit more about props and states. Props and state are related. The state of one component will often become the props of a child component. Props are passed to the child within the render method of the parent as the second argument to React.createElement() or, if you're using JSX, the more familiar tag attributes.
<MyChild name={this.state.childsName} />
The parent's state value of childsName becomes the child's this.props.name. From the child's perspective, the name prop is immutable. If it needs to be changed, the parent should just change its internal state:
this.setState({ childsName: 'New name' });
and React will propagate it to the child for you. A natural follow-on question is: what if the child needs to change its name prop? This is usually done through child events and parent callbacks. The child might expose an event called, for example, onNameChanged. The parent would then subscribe to the event by passing a callback handler.
<MyChild name={this.state.childsName} onNameChanged={this.handleName} />
The child would pass it's requested new name as an argument to the event callback by calling, e.g., this.props.onNameChanged('New name'), and the parent would use the name in the event handler to update its state.
handleName: function(newName) {
this.setState({ childsName: newName });
}