I'm a newbie in React, and I'm working on a project for a Public Health Unit named 'Gully Clinic' using Material UI and Redux Toolkit.
I believe if you have worked on a React project then it wouldn't be soon enough to come across component state management. I think this one of those basics you learn when you begin learning React.
The syntax goes like this for a functional component -
import { useState } from 'react';
const CustomInput = (props) => {
const [value, setValue] = useState('');
return <>
...
</>
}
In case you are wondering what are those empty <></>
brackets, they are the shorthand form for <React.Fragment></React.Fragment>
. You can find more on this in the official docs.
This was a component which made use of a single state value.
In a real-world scenario, this is not the only case and there are multiple state values to be stored and handled.
For example, if you have a data grid whose pageSize
needs to be managed via state along with values for various filters, all of which could be managed via a single state, say like this -
import { useState } from 'react';
const EmployeeDataGrid = (props) => {
const [state, setState] = useState({
pageSize: 5,
nameFilter: '',
designationFilter: '',
});
}
To update a state, for example when pageSize
is changed via some user interaction, for a such a scenario the best practice is to set the state as shown below -
...
const onPageSizeChange = (newPageSize) => {
setState((prevState) => {
return {
...prevState,
pageSize: newPageSize,
}
})
}
Here we are using the function argument variant of the setState method
Another scenario is wherein you need to update multiple state values together, say for example you provide the user to reset all the filters at once with a button interaction which you'd handle using an event listener like resetFilters
-
...
const resetFilters = () => {
setState((prevState) => {
return {
...prevState,
nameFilter: '',
designationFilter: '',
}
})
}
If you notice, if there are many such interactions in your app which changes the state, then eventually you'll have many functions or event listeners with this piece of code setState((prevState) => { ... })
in them. For me, this became a problem because it began to reduce the readability of the code and the unnecessary increase in the component code size.
The updateState
function along with setState
So, I wrote the updateState
function in the component itself which would accept partial state key value pairs and update the state. Take a look -
...
const updateState = (newState) => {
setState((prevState) => {
return {
...prevState,
...newState
}
})
}
// usage
const resetFilters = () => {
updateState({
nameFilter: '',
designationFilter: '',
})
}
Adding updateState
to the components was repetitive because every stateful component needed updateState
. So, I extracted out it to a separate individual utility function named useObjectState
which return the updateState
along with the usual state
object and setState
function.
import { useState } from 'react';
export const useObjectState = (initialState) => {
const [state, setState] = useState(initialState);
const updateState = (newState) => {
setState((prevState) => {
return {
...prevState,
...newState
}
});
}
return [state, setState, updateState];
};
If you liked this post, may be found it useful in someway or have something to say just let me know in the comments. :)
Important Note
You may say updateState
is not required as this is handled already by setState
as stated in the official docs. If you've really worked with both the Class based components and functional components then you would notice that setState
doesn't work with partial objects in functional components. The type definition of SetStateAction
in the @types/react/index.d.ts
confirms this. You'll find in this file the following around line 885.
// Unlike the class component setState, the updates are not allowed to be partial
type SetStateAction<S> = S | ((prevState: S) => S);
Top comments (0)