简体   繁体   中英

Using React Hooks with more than one Key/Value Pair in State Object

I wonder what the best way is to define more than one key/value pair for the state in a Functional Component .

In a class I would initialithe State like

this.state = {
    first: 'foo',
    second: 'bar'
};

To update the State I call

this.setState({
    first: 'foobar'
    second: 'barfoo'
});

Now with React Hooks I initialize the State like so.

const [first setfirst] = useState('foo');
const [second, setSecond] = useState('bar');

To update the State I call

setFirst = 'foobar';
setSecond = 'barfoo';

But, imho, that is not ideal. I have to rewrite const [x, setX] = useState(...); everytime I want to add a new key/value pair to the State object . Boilerplate. I further always have to keep in mind the "setter" name of x , which is setX . That will get messy, if the State object grows.

It would be nicer if I could simply call

setState(first: 'foobar', second: 'barfoo');

But I am not sure how to initialize the State object properly/what is the best way to do that.

Using object as the initial value

You can use a javascript object as your value. This way you can put more variables in your object and in one place. So your code would be like below:

const [example, setExample] = useState({first:'foobar', second:barfoo''});

Then you can update it like this:

setExample({...example,first:'new foobar'})
setExample({...example,second:'new foobar second'})

This type of setting is deconstruct your previous values and is replacing your new values with the old ones.

Using this object you just need to add your new property to the initialize of example and to places which you need to set it.

As a complex example you can reach this link:

React Hooks useState() with Object


Notice (updating the variable)

If you just update it using {first:'new foobar'} and don't include the second in your properties you may loose the old value of second. So use the ...example to have the old value of second .

You can set the whole object using useState like as follows -

const [stateObj, setStateObj] = useState({first:'foobar', second:'barfoo'});

and then to update the state -

setStateObj({first:'foobarnew', second:'barfoonew'})

You can make your own hook to do this !

function useMultipleStates() {
    const [first setFirst] = useState('foo');
    const [second, setSecond] = useState('bar');

    const setState = (f, s) => {
        setFirst(f);
        setSecond(s);
    }

    return {
        first,
        second,
        setState,
    }
}

You can adapt this to your needs, but if should give you an idea on how to do it.

From React docs : useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. useReducer also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks.

const initialState = { first: '', second: '' };

function reducer(state, action) {
  switch (action.type) {
    case 'doFirst':
      return {...state, first: 'newFirst' };
    case 'doSecond':
      return {...state, second: 'newSecond' };
    default:
      throw new Error();
  }
}

function Component() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      {state.first}
      {state.second}
      <button onClick={() => dispatch({type: 'doFirst'})}></button>
      <button onClick={() => dispatch({type: 'doSecond'})}></button>
    </>
  );
}

I would suggest to go for reducer hooks. React official site says if you have complex state rather go for userReducer hook.



const initialState = {
first: 'foo',
second: 'bar'
};

function reducer(state, action) {
  switch (action.type) {
    case 'updateFirst':
      return {...state, first: 'fooBar' };
    case 'updateSecond':
      return {...state, second: 'barfoo' };
    case 'updateBoth':
      return {...state, second: 'barfoo',first: 'fooBar' };
    default:
      throw new Error();
  }
}

function Component() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      {state.first}
      {state.second}
      <button onClick={() => dispatch({type: 'updateFirst'})}>UpdateFirst</button>
      <button onClick={() => dispatch({type: 'updateSecond'})}>UpdateSecond</button>
      <button onClick={() => dispatch({type: 'updateBoth'})}>UpdateBoth</button>
    </>
  );
}


Code : https://codesandbox.io/s/busy-rosalind-9oiow

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM