Реагируйте на ловушки, как лучше обновлять несколько состояний на основе смены реквизита - PullRequest
1 голос
/ 06 июня 2019

Допустим, у меня есть таблица с данными сортировки, и я хочу сохранить ее в состоянии (или даже в 3 отдельных состояниях). Предположим, это состояние может быть изменено ребенком. Есть ли способ сделать это , не имея 3 различных useEffects , я хотел бы узнать, возможно ли достичь того же, что и ниже, с только 1 эффектом использования

import React, { useState, useEffect } from "react";

function Table({ initialSortDirection, initialSortParam, initialSortEnabled }) {
    const [currentSortData, setSortData] = useState({
        sortDirection: initialSortDirection,
        sortParam: initialSortParam,
        hasSort: initialSortEnabled
    });
    useEffect(() => {
        setSortData({ ...currentSortData, sortDirection: initialSortDirection });
    }, [initialSortDirection]);
    useEffect(() => {
        setSortData({ ...currentSortData, sortParam: initialSortParam });
    }, [initialSortParam]);
    useEffect(() => {
        setSortData({ ...currentSortData, hasSort: initialSortEnabled });
    }, [initialSortEnabled]);
   return (<SomeComponent onChangeSort={setSortData} />)
}

По старому стилю я, вероятно, использовал бы componentWillReceiveProps и просто сравнил бы nextProps, чтобы увидеть, изменились ли они, но сейчас мне сложно найти краткий способ сделать это "сразу" и только при изменении .

В качестве наглядного примера рассмотрите изображение ниже, вы можете изменить сортировку, щелкнув по ячейке или изменив «ручки». enter image description here РЕДАКТИРОВАТЬ 1

Предположим, что другие состояния могут повлиять на состояние, и я не хочу переопределять обновленное состояние неизменным начальным пропеллером. Я обновил код соответственно

РЕДАКТИРОВАТЬ 2 Добавлена ​​картинка в сборник рассказов

Ответы [ 2 ]

2 голосов
/ 06 июня 2019

У вас может быть один useEffect(), который прослушивает изменение нескольких состояний:

useEffect(() => {
  setSortData({
    ...currentSortData,
    sortDirection: initialSortDirection,
    sortParam: initialSortParam,
    hasSort: initialSortEnabled
  });
}, [initialSortDirection, initialSortParam, initialSortEnabled]);
1 голос
/ 06 июня 2019

Это поведение, которое вы ищете?

Вот как я бы сделал это только с одним 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>
...