In a classical component the entire state is available as a single object this.state = {}, I was wondering if there's a similar way you could access the state in a functional component? You can access individual properties via their variable names but I'm wondering if there's a way to access all of them at once as if they were stored in an overarching object, similar to a class component.
No, there's no consolidated state object you can get access to that has all of the state members you've set up via useState.
You could store all of your component state in a single object if you want (this is even mentioned in the useState docs when talking about callback updates). For instance:
const [state, setState] = useState({
name: "",
profession: "",
age: null,
// ...
});
To update any individual state member, you have to handle creating the entire new object yourself (state setters from useState don't do the merging that Component.prototype.setState does). For instance, setting the age:
setState(state => ({
...state,
age: 42,
}));
It's important to use the callback form (as is always the case when setting state based on existing state).
But unless you do that, no, there's no one single object you have access to.
Related
I have an object variable within the state of my react app. I initialize it with the structure that I want the object to have. Late I am trying to update that object using the setState function. My issue is, I can't get it to actually update anything within the state. The way my code currently looks is:
// the initial state
var initialState = {
object: {
foo: '',
bar: 0,
array: [<an array of objects>]
}
};
// in componentDidMount
this.state = initialState;
// updating the object that is within the state (also in componentDidMount)
let object = {
foo: 'Value',
bar: 90,
array: [<a populated array of objects>]
};
this.setState(prevState => ({
...prevState.object,
...object
}));
console.log(this.state.object); // returns the object defined in initial state
I am really not sure how to fix this issue. I have also been trying a few other methods (especially the ones outlined in this post: Updating an object with setState in React
I have not tried every method outlined in that post but the ones I have been trying have not been working and I figure that this means it is a mistake that does not involve which method I am using. Any insight into this issue would be greatly appreciated. I tried to make this code as concise as possible but if you want to see the exact code I am using (which is pretty much just this but more) just ask.
Edit 2
You have to care each object key equality.
You can do this.
this.setState((prevState) => {
console.log('logging state: ', prevState)
return {
...prevState.object,
object:{ ...object }
})
)}
I'm reviewing a React Component and it contains a state property as well as an allData property.
To follow best practice, shouldn't allData be a part of state?
constructor(props) {
super(props);
this.allData = [];
this.state = {
allDisplayedData: [],
allRowsCount: -1,
favData: [],
favRowsCount: -1,
};
this.searchAll = this.searchAll.bind(this);
this.handleCellClick = this.handleCellClick.bind(this);
}
If you want the component to re-render on changing it, then it needs to be in state, otherwise put it wherever. Any instance variables other than this.state aren't part of React's control, so they don't have the same ability to set using setState. This means that they don't re-render the component like the state does.
Essentially, it depends on what you do with it and how you want to work with it.
I tend to use this pattern for things like cancelTokens and intervalIds and other data I might need later, but don't need as part of the state because it's only needed in unmount or update but not in the render itself.
If it's needed in the render, you should have it in state or be prepared to deal with the component not rendering when it's updated.
If you want to make the array part of state, then yes, if no, then no.
Other than the two previous detailed answers, I found the following statement at https://reactjs.org/docs/state-and-lifecycle.html
While this.props is set up by React itself and this.state has a
special meaning, you are free to add additional fields to the class
manually if you need to store something that doesn’t participate in
the data flow (like a timer ID).
I can't find answer so, this is my question. What is better practice using hooks like that with spread operator?
const [user, setUser] = useState({name: 'John', email: 'john#john.pl'})
setUser(prev => {...prev, name: 'New name'})
Or making state per properties?
const [name, setName] = useState('John')
setName('New name')
const [email, setEmail] = useState('john#john.pl')
setEmail('New email')
What is better option and why?
Clearly the 2nd one since you don't need to pass around the whole user state on each state update but just the user's name or email. Try to keep it simple where ever you can.
please read this info in react docs.
https://reactjs.org/docs/hooks-faq.html#should-i-use-one-or-many-state-variables
The both approaches has pros and cons.
Some important hightligts from docs:
we recommend to split state into multiple state variables based on
which values tend to change together.
Both putting all state in a single useState call, and having a
useState call per each field can work. Components tend to be most
readable when you find a balance between these two extremes, and group
related state into a few independent state variables. If the state
logic becomes complex, we recommend managing it with a reducer or a
custom Hook.
Usually it's better to have simple state when using hooks, since setState() works a bit different than this.setState() in class components - it not merges changes, but just update those:
// in class component
this.setState({ name: 'Hello' }); // update only name field of state
// in functional component
setState({ name: 'Hello' }); // sets { name: 'Hello' } as new state
For complex state you can use useReducer() hook.
hooks state easy to use than setState. You can use hooks with spread operator like this
const [user, setUser] = useState({name: 'John', email: 'john#john.pl'});
setUser({...user, name: 'New name'});
If I'm passing (a reference to) an Object as a prop is it OK to mutate values in the prop?
I'm developing a web app which will require a lot of values to be passed to a component, and I'm trying to find the best way of passing the values to the component and back to the parent.
From everything I've read mutating a prop is the wrong way to do things, because next time the component is updated the values are passed back to the child component overwriting the mutations. But only the reference to the object is passed so any mutations to the values in the object prop happen to the original object in the parent component. Also Vuejs does not complain about mutating props when this happens.
const subComponent = {
name: "subComponent",
template: `
<div>
Sub Component Input
<input type="text" v-model="objectProp.val1"></input>
</div>`,
props: {
objectProp: {
required: false,
default: () => {return {val1: "carrot"}}
}
}
}
const aComponent = {
name: "aComponent",
template: `
<div>
val1: {{mainObject.val1}}
val2: {{mainObject.val2}}
<sub-component :objectProp="mainObject"></sub-component>
</div>`,
data: function() {
return{
mainObject: {
val1: "foo",
val2: "bar"
}
}
},
components: {
subComponent
}
}
new Vue({
el: "#app",
components: {
aComponent
}
})
Here is a JSFiddle showing an object prop being mutated.
JSFiddle
Is mutating a prop bad practice?
Yes absolutely. In more complex applications it is very easy to lose track of where/what/why is mutated
What is the right way to handle state across different components?
In small projects you can really do whatever you want, because you will most likely be able to follow the logic - even after not looking at the project for a year. The possibilities include:
Mutating Props (ugly but will work)
Using Events to mutate state in parent components; take a look at the EventBus (better)
Use global shared state; look at Vuex (best, but a little more boilerplate)
In big projects, however, you should absolutely use Vuex. It is a module for Vue that adds global shared state to your app, which you can access and mutate from all places in your app.
I think I understand what you are trying to do, You want to pass data to a child component, mutate it and then give that data back to the parent component.
You never want to mutate the props data given to the child component, however you CAN mutate a local state of the data, which could be an exact clone of the prop.
You can do this in many ways, I normally use a computed property as suggested in the Vue documentation:
https://v2.vuejs.org/v2/guide/components-props.html
in the computed return, just return the data coming in from the property.
For example, if I want to do any operation on this.state or some other object, such as Object.keys(this.state).map() to get access to all the values in the object.
Is it bad practice to do this?
Object.keys(this.state).map(k => this.state[k]);
Thanks
In React, you should only mutate this.state using this.setState() so that React knows when to re-render components.
The line of code you've written is fine, because you're not actually modifying the state object. You've already created a new array using Object.keys.
If however, you want to copy this.state without modifying it, try the following.
const state = {...this.state};
// Or
const state = Object.assign({}, this.state);
React Mutating State.
let state = {
age : 25,
name : 'Robin',
friends: ['Barney', 'Ted']
}
Change Age
this.setState({age: 26})
Change Name
this.setState({name: 'Lily'})
Add Friend
this.setState({
friends: this.state.friends.concat(['Marshall'])
})
Try this library immutability-helper for complex state updates.