Mutating props in React - javascript

I have a React component which receives an array or objects via props. Something I would like to do is have an event re-order these props. However, it seems that React re-rendering only occurs when state changes.
Right now I have the ordering handled in the parent object and pass the method to handle the ordering through as a prop, but ideally I want the component responsible for rendering these objects to also handle the ordering.
Chucking props into state seems bad, but what's the best thing to do here?

Props are immutable, but in your case it seems that your data does not change, only the sort order changes, so you can:
keep your data and sort functions as props
store your sort order in state
maybe use getInitialState to return the default sort order
when sort order is changed, state is set so re-render happens

As i understand React needs to change the state to trigger the render. If you want to keep the sort logic attached to you component you have to create a copy of the array.
getInitialState: function () {
return {
items: this.props.items.slice(0)
};
},
As implemented here.

Related

React classes in main component constructor

Let's say I have a lot of app state to manage in my React application.
Therefore, I would like to split the state into smaller, manageable chunks.
For example I have the following main component with state and methods that alter this state.
class App extends Component {
constructor(props) {
super(props);
this.state = {
foo: ['some', 'items'],
bar: [{ arr: 'of objects'}]
}
}
changeFoo() {some code in here...}
changeBar() {some code in here...}
}
The state and methods written in the App component are getting out of hand. Yet it must be written in the App component since the state is passed to other components as props.
How would you usually manage this?
When you see that the state of your React application is getting out of hand, it's usually time to bring in a state management library like Redux (there're a few and Redux is the most popular one).
It'll help you have a global state that is managed in a reasonable way.
When we see how React works. It is based on one-directional data flow.
So, usually the Application state is kept at the top most Component (Say, App Component) in your case. So that data/state can be passed down as props to the component that needs it.
There, however may be the cases where children components of the parent, needs to work with the same data(Say in case of an event - a button click that happens in the child component.) In that case we write a function in the parent component and pass the function as props to the children, so that the state gets updated in the parent itself and any child gets updated data.
In pure React (without using any state management library), we have to pass the state as props to work with our app. But in case you choose to use a state management library such as Redux, then the components (known as Containers) can directly communicate with the Application State.
And If your application state contains objects within objects(like you have shown) or Array of Objects containing more Objects, then you cannot use setState() to update the state directly. In most of the cases, you take copy of the state and then use JSON.parse(JSON.stringify(state)) to do deep cloning and work with the state in a best possible manner.
There are other things in the example, the functions that you have used within the class , you need to bind the scope of this variable to point to the current class. This we do inside the constructor method, or simple make use of arrow function in order to avoid errors.
If you need more explanation, I will share with you :)
One solution is to make a generic change() function with a parameter for the key that should be changed:
change(key, value) {
setState({key: value, ...this.state});
}
Now when you want to add a listener to a child component:
<Foo onChange={ value => change('foo', value) }/>
<Bar onChange={ value => change('bar', value) }/>

How should the react component re-render itself when props from redux have been updated?

I have a "checkProps()" function that checks if props are empty or not and renders the view if so.
Right now runs on every view render, but since the fn checks just the props, and those come from the redux mapper I think is not a very good approach, performance-wise talking.
I have considered use "componentWillReceiveProps/getDerivedStateFromProps" but according to some sites, that might be an antipattern and I should avoid the use of those methods.
What should be the right way to perform props-ops just when the props are updated and not on every render?
To perform custom comparison in props (not just shallow) you should use [componentDidUpdate][1] which provides you prevProps and prevState to compare with the current ones:
componentDidUpdate(prevProps){
if(prevProps.items.length !== this.props.items.length)
this.setState({items: this.props.items})
}

Why React keep componentWillReceiveProps and shouldComponentUpdate methods both?

when i use react ,i find these two life cycle are too similar, componentWillReceiveProps receive nextProps as argument, shouldComponentUpdate receive nextProps and nextState as arguments, so i think shouldComponentUpdate can do the same thing and more, why react keep componentWillReceiveProps method, i wonder what's difference between these two methods
They have two different roles and execute on different situations:
shouldComponentUpdate will be called every time a prop or something in the state changes (or React think that has changed). It's function is to determine if the component should re-render by returning a boolean: true if the component should re-render (this is the default return value), or false if it shouldn't.
You can access the current and next state and props, to compare and decide if it really should re-render or not. You should not use this method for other reason.
On the other side, componentWillReceiveProps will only be called if the props changed (or seem to have changed). If only the state changes, this method won't be called.
Also, this won't decide if the component should re-render. You can use this method to, for example, change some state, or make an API call.
Check out these links:
componentWillReceiveProps: https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/component_will_receive_props.html
shouldComponentUpdate: https://developmentarc.gitbooks.io/react-indepth/content/life_cycle/update/using_should_component_update.html
componentWillReceiveProps - as the function name states this is called whenever new props will be passed to the component and you can trigger an action depending on the new prop state
shouldComponentUpdate - is a filter function which decides if the component tree should be re-rendered. This function can serve as an additional filter where you change are happening which don't require a re-render
More info here

react.js does not update DOM after having changed state array

I am trying to implement a game in react where I have the board as an two dimensional array in the initial state of the parent class. Tiles are rendered by iterating through that array. I pass those children a function as a prop so that they can change that state array.
Now, when I use that function to change the array, the HTML does not update. The array gets updated when I call setState but it never rerenders. I tried this.forceUpdate() but still no luck. What I then did was to pass a function from that child to the parent through the function to update that child's state and this works, but I need the function from the parent to call itself recursively to update the board. I feel like I might have hit an anti-pattern. How could I change my code in order for the DOM to update, please?
There is parts missing but those are all the components involved. statusBoard is the internal version of the board featuring the solution. I hope this is clear.
Whenever you are linking props and state together you have to create a componentWillReceiveProps function like so:
componentWillReceiveProps: function(nextProps) {
this.setState({
positionX: nextProps.columnPosition,
positionY: nextProps.rowPosition
});
}
When games state changes and passes it down as props to Field, fields own internal state doesn't get updated at that point because it is relying on its own state. this is an anti pattern and you should avoid Field having to have any state and just rely on its props it gets passed and have a parent component that is handling the state of everything.
https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html

React - updating state during render produces errors

I'm new to React and am trying to update the state of a parent component from the child everytime an onChange action happens. The onchange action comes from an input box that when letters are typed it updates the state of searchInputVal with the value of what has been typed. I have a parent <App/> component with the following properties and states here:
updateSampleFilteredState(filteredSamples) {
this.setState({
samples: filteredSamples
});
},
getInitialState () {
return {
samples:allSamples,
searchInputVal:""
}}
I pass the properties and states down to a child component here:
updateNewSampleState(filteredSamples){
return (
this.props.updateSampleFilteredState(filteredSamples)
)
}
render() {
const filteredSamples = this.props.samples.filter(sample => {
return sample.sampleFamily.toLowerCase().indexOf(this.props.searchInputVal.toLowerCase()) !== -1;
});
this.updateNewSampleState(filteredSamples);
return <div className="samples-container-inner-styling">
{
filteredSamples.map((sample) => {
return (...
Before I added the line this.updateNewSampleState(filteredSamples); the child component would render out the filtering just fine but obviously not update the state of sample with the new filtered state. When I the line this.updateNewSampleState(filteredSamples); to execute the function in the component to set the new state I get a list of re-occuring errors that eventually make my app crash. The errors say something about an anti pattern. I'm not sure how else to update the state?
You should't be updating the state from the render function, and you are facing the reason why that's a bad way to do things. Every time you call the setState the component re-renders, so if you call it inside the render function it will be called again and so on... You should ask yourself why are you calling that function there. I guess you could just do it in the onChange function you are using for the input.
As already mentioned by #César, setting the state in the renderer doesn't make sense, since setting the state triggers a rerender of the component, so you basically get something like an infinite render loop.
Given that you are computing filteredSamples only from the props, you could compute that state in the constructor:
The constructor is the right place to initialize state.
However, note the following when deriving state from props in the constructor:
It's okay to initialize state based on props if you know what you're doing. [...]
Beware of this pattern, as it effectively "forks" the props and can lead to bugs. Instead of syncing props to state, you often want to lift the state up.
If you "fork" props by using them for state, you might also want to implement componentWillReceiveProps(nextProps) to keep the state up-to-date with them. But lifting state up is often easier and less bug-prone.

Categories

Resources