在状态对象中使用具有多个键/值对的 React Hooks

Posted

技术标签:

【中文标题】在状态对象中使用具有多个键/值对的 React Hooks【英文标题】:Using React Hooks with more than one Key/Value Pair in State Object 【发布时间】:2019-12-09 19:41:04 【问题描述】:

我想知道最好的方法是在Functional Component 中为state 定义多个key/value 对。

在课堂上我会像State一样初始化

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

更新State我打电话

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

现在使用React Hooks,我像这样初始化State

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

更新State我打电话

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

但是,恕我直言,这并不理想。每次我想向State object 添加一个新的key/value 对时,我都必须重写const [x, setX] = useState(...);。样板。我还必须始终牢记x 的“setter”名称,即setX。如果State object 增长,那将变得一团糟。

如果我能简单地打电话就更好了

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

但我不确定如何正确初始化State object/最好的方法是什么。

【问题讨论】:

您找到了最好的方法吗?我想避免在使用 setState 时重新渲染多个子组件 @UMR 使用接受的答案。 但你忘了接受答案...我使用 React.memo 和 useReducer @Stophface 的组合 @UMR 有一个接受的答案,有七个赞成票……来自 Monika Mangal 的那个。 Alireza HI 提供的答案也有效……仔细观察。我觉得你想达到的和我想做的不一样。 【参考方案1】:

使用对象作为初始值

您可以使用javascript object 作为您的值。 通过这种方式,您可以将更多变量放在您的对象和一个地方。 所以你的代码如下:

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

然后你可以像这样更新它:

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

这种类型的setting 正在解构您以前的值,并用旧值替换您的新值。

使用此对象,您只需将新的property 添加到example 的初始化以及您需要设置它的位置。

作为一个复杂的示例,您可以访问此链接:

React Hooks useState() with Object


注意(更新变量)

如果您只是使用first:'new foobar' 更新它并且不在您的属性中包含second,您可能会丢失第二个的旧值。所以使用...example 来获得second 的旧值。

【讨论】:

【参考方案2】:

你可以自己做一个钩子来做这个!

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

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

    return 
        first,
        second,
        setState,
    

您可以根据自己的需要进行调整,但如果应该让您知道如何做到这一点。

【讨论】:

那是更多样板、开销、错误加载。【参考方案3】:

您可以使用 useState 设置整个对象,如下所示 -

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

然后更新状态 -

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

【讨论】:

如果您没有像这样设置所有状态,请不要忘记传播state。旧this.setState() 更新相关属性并将更改的属性与状态合并,但使用钩子时,状态总是被覆盖。【参考方案4】:

来自 React 文档:当您有涉及多个子值的复杂状态逻辑或下一个状态取决于前一个状态时,useReducer 通常比useState 更可取。 useReducer 还允许您优化触发深度更新的组件的性能,因为您可以向下传递调度而不是回调。

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>
    </>
  );

【讨论】:

【参考方案5】:

我建议使用减速器挂钩。 React 官方网站说如果你有复杂的状态,宁愿去 userReducer 钩子。



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>
    </>
  );



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

【讨论】:

对于这么简单的事情来说太多样板文件了

以上是关于在状态对象中使用具有多个键/值对的 React Hooks的主要内容,如果未能解决你的问题,请参考以下文章

Restkit 返回具有 0 个键值对的对象数组

获取具有特定键/值对的二维数组中的子数组

JS基础 Map是一组键值对的结构

无法跟踪实体类型的实例,因为已经在跟踪具有相同键值对的另一个实例 'Id'

如何在 Typescript 中将具有动态键的对象设置为 React 状态

在 react 中使用 setState 将预定义的对象推送到数组中