I have a question, if I can use useState
generic in React Hooks, just like I can do this in React Components while managing multiple states?
state = {
input1: "",
input2: "",
input3: ""
// .. more states
};
handleChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value,
});
};
I have a question, if I can use useState
generic in React Hooks, just like I can do this in React Components while managing multiple states?
state = {
input1: "",
input2: "",
input3: ""
// .. more states
};
handleChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value,
});
};
Share
Improve this question
edited Feb 11, 2021 at 10:39
Dennis Vash
53.9k11 gold badges116 silver badges132 bronze badges
asked Jul 9, 2019 at 10:29
MateuszMateusz
952 gold badges2 silver badges7 bronze badges
3
- Do you mean doing this with state variables? If you are using more plex state then obviously this can be done similar to how it's done in your class ponent example. For the former, see my answer which demonstrates the ability to set variable state in a dynamically. – James Commented Jul 9, 2019 at 10:39
-
@ravibagul91 not necessarily, you can manage plex state with
useState
– James Commented Jul 9, 2019 at 10:40 - @James Yeah, that's what I'm looking for. I'll delve into your linked answer – Mateusz Commented Jul 9, 2019 at 10:48
3 Answers
Reset to default 12Yes, with hooks you can manage plex state (without 3rd party library) in three ways, where the main reasoning is managing state ids and their corresponding elements.
- Manage a single object with multiple states (notice that an array is an object).
- Use
useReducer
if (1
) is too plex. - Use multiple
useState
for every key-value pair (consider the readability and maintenance of it).
Check out this:
// Ids-values pairs.
const plexStateInitial = {
input1: "",
input2: "",
input3: ""
// .. more states
};
function reducer(state, action) {
return { ...state, [action.type]: action.value };
}
export default function App() {
const [fromUseState, setState] = useState(plexStateInitial);
// handle generic state from useState
const onChangeUseState = (e) => {
const { name, value } = e.target;
setState((prevState) => ({ ...prevState, [name]: value }));
};
const [fromReducer, dispatch] = useReducer(reducer, plexStateInitial);
// handle generic state from useReducer
const onChangeUseReducer = (e) => {
const { name, value } = e.target;
dispatch({ type: name, value });
};
return (
<>
<h3>useState</h3>
<div>
{Object.entries(fromUseState).map(([key, value]) => (
<input
key={key}
name={key}
value={value}
onChange={onChangeUseState}
/>
))}
<pre>{JSON.stringify(fromUseState, null, 2)}</pre>
</div>
<h3>useReducer</h3>
<div>
{Object.entries(fromReducer).map(([key, value]) => (
<input
name={key}
key={key}
value={value}
onChange={onChangeUseReducer}
/>
))}
<pre>{JSON.stringify(fromReducer, null, 2)}</pre>
</div>
</>
);
}
Notes
- Unlike the
setState
method found in class ponents,useState
does not automatically merge update objects. You can replicate this behavior by bining the function updater form with object spread syntax:
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
Refer to React Docs.
The correct way to do what you're trying to do is to create your own hook that uses useState
internally.
Here is an example:
// This is your generic reusable hook.
const useHandleChange = (initial) => {
const [value, setValue] = React.useState(initial);
const handleChange = React.useCallback(
(event) => setValue(event.target.value), // This is the meaty part.
[]
);
return [value, handleChange];
}
const App = () => {
// Here we use the hook 3 times to show it's reusable.
const [value1, handle1] = useHandleChange('one');
const [value2, handle2] = useHandleChange('two');
const [value3, handle3] = useHandleChange('three');
return <div>
<div>
<input onChange={handle1} value={value1} />
<input onChange={handle2} value={value2} />
<input onChange={handle3} value={value3} />
</div>
<h2>States:</h2>
<ul>
<li>{value1}</li>
<li>{value2}</li>
<li>{value3}</li>
</ul>
</div>
}
ReactDOM.render(<App />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Note the use of React.useCallback to stop your hook from returning a new handler function on every render. (We don't need to specify setValue
as a dependency because React guarantees that it will never change)
I didn't actually test this, but it should work.
See https://reactjs/docs/hooks-reference.html#usestate for more info.
import React, {useState} from 'react';
const MyComponent = () => {
const [name, setName] = useState('Default value for name');
return (<div><button onClick={()=>setName('John Doe')}}>Set Name</button></div>);
};
export default MyComponent;