reactjs rendering with state or props - reactjs

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

Related

React JS - how to read specific attribute from a child JSX before mounting it to the DOM

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:

REACT: How do you set a child component's state to its parent's state?

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;

If React props are readonly, how they can change (whats the usage of getDerivedStateFromProps)?

I'm learning React. I learned that props in react are readonly.
But i read somewhere:
getDerivedStateFromProps updates the state based on prop changes
So i got confused. If props are readonly, how they can change?
They are readonly in the context of a component, meaning, you can't assign a new value to them.
But a parent that passes props to child, can pass different props based on some condition. In that case, the child get rendered with a different props.
Example:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0,
};
}
render() {
return (
<div>
<Child prop1={this.state.value} />
<button onClick={() => this.setState({ value: this.state.value + 1 })}>Click me</button>
</div>
);
}
}
In my example, each click on the parent's button will change it state, therefore, React will re-render it, and then this parent will pass a new value to Child component.
I think you need to understand component life-cycle and how to use and handle props which is described beautifully in below links:
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
https://reactjs.org/docs/components-and-props.html#props-are-read-only
Props are read only means you can't change the value, but it doesn't mean you can't update it, for that you need to pass updated props back to child component and go any lifecycle methods to it.
An update can be caused by changes to props or state.
when there is update render() method is get called.
you are saying update to props, which directly means you are changing and modifying child,
props changed means, the data passed from parent is changed which leads in changing props,
always remember state passed from parent is considered as props for child is key point.
static getDerivedStateFromProps(props, state) gets called right after render() used rarely mailnly for animations transitions purposes.
the things possible with componentWillRecieveProps() and componentDidUpdate() is now done by getDerivedStateFromProps(), it will return object in response to change in props, and null if no change, sounds wonderful.
as you can see method is static you cant change any data, you can just play with your nextProps and prevState only.
this is useful for components having async api calls.

`componentWillReceiveProps` explanation

I recently wanted to upgrade my knowledge of React, so I started from the component lifecycle methods. The first thing that got me curious, is this componentWillReceiveProps. So, the docs are saying that it's fired when component is receiving new (not necessarily updated) props. Inside that method we can compare them and save into the state if needed.
My question is: Why do we need that method, if changes in props of that component (inside parent render) will trigger the re-render of this child component?
One common use case are state (this.state) updates that may be necessary in response to the updated props.
Since you should not try to update the component's state via this.setState() in the render function, this needs to happen in componentWillReceiveProps.
Additionally, if some prop is used as a parameter to some fetch function you should watch this prop in componentWillReceiveProps to re-fetch data using the new parameter.
Usually componentDidMount is used as a place where you trigger a method to fetch some data. But if your container, for example, UserData is not unmounted and you change userId prop, the container needs to fetch data of a user for corresponding userId.
class UserData extends Component {
componentDidMount() {
this.props.getUser(this.props.userId);
}
componentWillReceiveProps(nextProps) {
if (this.props.userId !== nextProps.userid) {
this.props.getUser(nextProps.userId);
}
}
render() {
if (this.props.loading) {
return <div>Loading...</div>
}
return <div>{this.user.firstName}</div>
}
}
It is not a full working example. Let's imagine that getUser dispatch Redux action and Redux assign to the component user, loading and getUser props.
It 'serves' as an opportunity to react to the incoming props to set the state of your application before render. If your call setState after render you will re-render infinitely and that's why you're not allowed to do that, so you can use componentWillReceiveProps instead.
But... you are beyond CORRECT in your confusion, so correct in fact that they are deprecating it and other Will-lifecycle hooks Discussion Deprecation.
There are other ways to accomplish what you want to do without most of those Will-lifecycle methods, one way being don't call setState after render, just use the new incoming props directly in render (or wherever) to create the stateful value you need and then just use the new value directly, you can then later set state to keep a reference for the next iteration ex: this.state.someState = someValue, this will accomplish everything and not re-render the component in an infinite loop.
Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render.
Look at this article
the componentWillReceiveProps will always receive as param "NxtProps", componentWillReceiveProps is called after render().
some people use this method use this to compare nxtProps and this.props to check, if something should happen before the component call render, and to some validations.
check the react's documentation to know more about react lifecycle!
hope this could help you!
changes in props of that component (inside parent render) will trigger the re-render of this child component
You are absolutely right. You only need to use this method if you need to react to those changes. For instance, you might have a piece of state in a child component that is calculated using multiple props.
Small Example:
class Test extends Component {
state = {
modified: "blank"
};
componentDidMount(){
this.setState({
modified: `${this.props.myProp} isModified`
});
}
componentWillReceiveProps(nextProps) {
this.setState({
modified: `${nextProps.myProp} isModified`
});
}
render() {
return <div className="displayed">{this.state.modified}</div>
}
}
In this example, componentDidMount sets the state using this.props. When this component receives new props, without componentWillReceiveProps, this.state.modified would never be updated again.
Of course, you could just do {this.props.myProp + "IsModified"} in the render method, but componentWillReceiveProps is useful when you need to update this.state on prop changes.

React: Losing ref values

I am using two components and I am using this pattern: child component should stay isolated as much it can - it is handling its own validation error. Parent component should check for errors which have dependencies between children. So, in my case: password field and password confirmation field.
Here is my code:
a) SignUp (parent)
Setting initial state.
constructor() {
super();
this.state = {
isPasswordMatching: false
};
}
In render() method I am outputting my child component. Through prop called callback I am propagating method isPasswordMatching() by binding parent's this. The goal is that method can be called within child component.
<TextInput
id={'password'}
ref={(ref) => this.password = ref}
callback={this.isPasswordMatching.bind(this)}
// some other unimportant props
/>
<TextInput
id={'passwordConfirm'}
ref={(ref) => this.passwordConfirm = ref}
...
isPasswordMatching() method is checking if passwords match (through refs this.password and this.passwordConfirm) and then updates state. Please note that this method is called inside child (password or passwordConfirm).
isPasswordMatching() {
this.setState({
isPasswordMatching: this.password.state.value === this.passwordConfirm.state.value
});
}
b) TextInput (child)
Setting initial state.
constructor() {
super();
this.state = {
value: '',
isValid: false
};
}
On blur validation is done and state is updated.
onBlur(event) {
// doing validation and preparing error messages
this.setState({
value: value,
isValid: this.error === null
});
}
Latest. Callback prop is called.
componentDidUpdate(prevProps) {
if (prevProps.id === 'password' || prevProps.id === 'passwordConfirm') {
prevProps.callback();
}
}
Issue
Somehow my refs are lost. Scenario:
Parent component is renderder
Child components are rendered
I am entering one of input fields and get out (this invokes onBlur() method) - state gets updated, child component is rendered
componentDidUpdate() is invoked and prevProp.callback() as well
When going to isPasswordMatching() method I am outputting this.password and this.passwordConfirm - they are objects with expected values of reference. Updating state of parent - component gets rendered.
Then again all children are rendered, components get updated, callback is called but this time this.password and this.passwordConfirm are null.
I have no idea why references are kinda lost. Should I be doing something differently?
Thank you in advance.
See the react documentation here, with important warnings and advise about when to use or not to use refs.
Note that when the referenced component is unmounted and whenever the ref changes, the old ref will be called with null as an argument. This prevents memory leaks in the case that the instance is stored, as in the second example. Also note that when writing refs with inline function expressions as in the examples here, React sees a different function object each time so on every update, ref will be called with null immediately before it's called with the component instance.
I'm not sure if this answers #be-codified's question for not, but I found this running into a similar issue. In my case, it turned out that it was due to using a functional component.
https://reactjs.org/docs/refs-and-the-dom.html#refs-and-functional-components
Refs and Functional Components
You may not use the ref attribute on functional components because they don’t
You should convert the component to a class if you need a ref to it, just like you do when you need lifecycle methods or state.
You can, however, use the ref attribute inside a functional component as long as you refer to a DOM element or a class component
The documentation explains what you should do to solve the issue if you have control of the component you're trying to render.
However in my case, the component was from a 3rd party library. So, simply wrapping the component worked fine.
Working
<div ref={element => this.elementName = element}>
<FunctionalComponent />
</div>
Not Working
sets this.elementName to null
<FunctionalComponent ref={element => this.elementName = element} />
Hope this helps anyone finding this question like I did.

Resources