React钩子如何根据道具更改更好地更新多个状态

时间:2019-06-06 07:58:00

标签: reactjs react-hooks

说我有一个包含排序数据的表,我想将其存储在state(甚至3个分离的状态)上。假设孩子可以改变这种状态。 无论如何,在没有3个不同的useEffects 的情况下进行此操作,我想看看是否有可能仅使用1个效果就能达到与以下相同的效果?

val

在过去的学校中,我可能会使用componentWillReceiveProps并仅比较nextProps来查看它们是否发生了变化,但是现在我很难找到一种简单的方法来“一次”且仅在更改时进行操作。 / p>

作为一个可视示例,考虑下面的图像,您可以通过单击单元格或更改“旋钮”来更改排序。 enter image description here 编辑1

假定其他因素可能影响状态,并且我不想使用未更改的初始prop覆盖更新的状态。我相应地更新了代码

编辑2 添加了故事书图片

3 个答案:

答案 0 :(得分:2)

您可以有一个useEffect()来监听很少的状态变化:

useEffect(() => {
  setSortData({
    ...currentSortData,
    sortDirection: initialSortDirection,
    sortParam: initialSortParam,
    hasSort: initialSortEnabled
  });
}, [initialSortDirection, initialSortParam, initialSortEnabled]);

答案 1 :(得分:1)

这是您要寻找的行为吗?

这就是我只用一个useEffect()的方式。

我会将props的最后一个值(来自先前的渲染)保留在useRef内,并检查每个属性的差异,并决定是否更新state。之后,我将ref的值更新为当前的props,以便在下一次渲染时对照将来的props进行检查,等等。

function App() {

const [initialState, setInitialState] = React.useState({
  initialProp1: 'A',
  initialProp2: 'A'
});

return(
    <Table
      {...initialState}
      setInitialState={setInitialState}
    />
  );
}

function Table({initialProp1, initialProp2, setInitialState}) {
  const [myState, setMyState] = React.useState({
    prop1: initialProp1,
    prop2: initialProp2
  });
  
  const lastProps = React.useRef({
    initialProp1, 
    initialProp2
  });
  
  React.useEffect(()=>{
    if (lastProps.current.initialProp1 !== initialProp1) {
      console.log('1 changed');
      setMyState((prevState)=>{
        return({
          ...prevState,
          prop1: initialProp1
        });
      });
    }
    if (lastProps.current.initialProp2 !== initialProp2) {
      console.log('2 changed');
      setMyState((prevState)=>{
        return({
          ...prevState,
          prop2: initialProp2
        });
      });
    }
    lastProps.current = {
      initialProp1,
      initialProp2
    }
  });
  
  function changeState() {
    setMyState((prevState) => {
      return({
        ...prevState,
        prop2: 'B'
      });
    });
  }
  
  function changeProps() {
    setInitialState({
      initialProp1: 'A',
      initialProp2: 'C'
    });
  }
  
  return(
  <React.Fragment>
    <div>This is Table <b>props</b> initialProp1: {initialProp1}</div>
    <div>This is Table <b>props</b> initialProp2: {initialProp2}</div>
    <div>This is Table <b>state</b> prop1: {myState.prop1}</div>
    <div>This is Table <b>state</b> prop2: {myState.prop2}</div>
    <button onClick={changeState}>Change Table state</button>
    <button onClick={changeProps}>Change props that comes from parent</button>
  </React.Fragment>
  );
  
}


ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

答案 2 :(得分:1)

当我面对类似的问题时遇到了这个问题,但是我对cbdevelopers对于他使用useRef的回答感到不满意,因为我印象中您不需要这个。一个对Reactflux友好的家伙指出了一个更优雅的解决方案:

const Table = (props) => {
    const { initialSortDirection, initialSortParam, initialSortEnabled } = props;

    const [currentSortData, setSortData] = useState({
        sortDirection: initialSortDirection,
        sortParam: initialSortParam,
        hasSort: initialSortEnabled
    });

    useEffect(() => {
        setSortData((prevSortData) => ({ 
            ...prevSortData, 
            sortDirection: initialSortDirection 
        }));
    }, [initialSortDirection]);
    useEffect((prevSortData) => {
        setSortData(() => ({ 
            ...prevSortData, 
            sortParam: initialSortParam 
        });
    }, [initialSortParam]);
    useEffect(() => {
        setSortData((prevSortData) => ({ 
            ...prevSortData, 
            hasSort: initialSortEnabled 
        }));
    }, [initialSortEnabled]);

   return (<SomeComponent onChangeSort={setSortData} />)
}

我知道您想将所有内容合并为一个,但是我不建议这样做。 您要分开关注点,始终在道具更新时发出正确的效果。

https://reactjs.org/docs/hooks-effect.html#tip-use-multiple-effects-to-separate-concerns

请注意,OP解决方案是虚假的,就像两个道具同时更新一样,当使用多种效果时,只有最后一个状态更改会持续存在。

希望这对某人有帮助。