Невозможно изменить состояние в заголовке таблицы материалов при использовании удаленных данных

Я поместил простое логическое состояние в настраиваемый заголовок, план состоит в том, чтобы сделать это состояние элементом управления раскрывающимся меню. Я использовал простой onClick для этого настраиваемого заголовка, который установил для состояний противоположное значение и после этого записал состояние. Но состояние остается прежним и не меняется при каждом нажатии.

Это происходит, когда я устанавливаю столбцы с начальным setState, потому что мне нужно, чтобы моя таблица была полностью на стороне сервера. При установке столбцов с нормальным пусть он работает, но это не особая необходимость.

заголовок выделен, щелкните по нему, и вы увидите журнал состояния в консоли.

export default function PositioningActionsColumn() {
  const [stateData, setStateData] = useState([]);
  const [stateColumns, setStateColumns] = useState([]);
  const [isOpen, setIsOpen] = useState(false);

  // setting the columns and data - will be from a fetch later
  useEffect(() => {
    setStateColumns([
      {
        title: nameHeader,
        field: "name"
      },
      {
        title: "Surname",
        field: "surname",
        initialEditValue: "initial edit value"
      },
      { title: "Birth Year", field: "birthYear", type: "numeric" },
      {
        title: "Birth Place",
        field: "birthCity",
        lookup: { 34: "İstanbul", 63: "Şanlıurfa" }
      }
    ]);
    setStateData([
      { name: "Mehmet", surname: "Baran", birthYear: 1987, birthCity: 63 },
      { name: "Zerya Betül", surname: "Baran", birthYear: 2017, birthCity: 34 }
    ]);
  }, []);

  const orderFunc = (orderedColumnId, orderDirection) => {
    console.log(
      "orderedColumnId:",
      orderedColumnId,
      "orderDirection:",
      orderDirection
    );
  };

  const searchFunc = e => {
    console.log(e);
  };

  const handleClick = () => {
    setIsOpen(!isOpen);
    console.log(isOpen);
  };

  const nameHeader = (
    <div style={{ background: "lightblue" }} onClick={handleClick}>
      Click on this custom Name Header
    </div>
  );

  return (
    <MaterialTable
      title="Editable Preview"
      icons={tableIcons}
      columns={stateColumns}
      data={stateData}
      onOrderChange={(orderedColumnId, orderDirection) => {
        orderFunc(orderedColumnId, orderDirection);
      }}
      onSearchChange={e => searchFunc(e)}
      options={{ draggable: false, selection: true, actionsColumnIndex: -1 }}
      actions={[
        {
          tooltip: "Remove All Selected Users",
          icon: "delete",
          onClick: (evt, data) => {
            console.log({ data });
            alert("You want to delete " + data.length + " rows");
          }
        },
        {
          isFreeAction: true,
          tooltip: "FreeAction",
          icon: () => <div>Free</div>,
          onClick: (evt, data) => {
            console.log({ data });
          }
        }
      ]}
      editable={{
        onRowAdd: newData =>
          new Promise((resolve, reject) => {
            setTimeout(() => {
              {
                console.log({ newData });
                const data = stateData;
                data.push(newData);
                setStateData(data, () => resolve());
              }
              resolve();
            }, 1000);
          }),
        onRowUpdate: (newData, oldData) =>
          new Promise((resolve, reject) => {
            setTimeout(() => {
              {
                console.log({ newData }, { oldData });
                const data = stateData;
                const index = data.indexOf(oldData);
                data[index] = newData;
                setStateData(data, () => resolve());
              }
              resolve();
            }, 1000);
          }),
        onRowDelete: oldData =>
          new Promise((resolve, reject) => {
            setTimeout(() => {
              {
                console.log({ oldData });
                let data = stateData;
                const index = data.indexOf(oldData);
                data.splice(index, 1);
                setStateData(data, () => resolve());
              }
              resolve();
            }, 1000);
          })
      }}
    />
  );
}

https://codesandbox.io/s/material-table-testing-actions-position-and-output-2-sj1tt


person Jordan    schedule 10.03.2020    source источник
comment
Я пытаюсь изменить состояние, но состояние, кажется, не меняется очень расплывчато. Пожалуйста, предоставьте более подробное объяснение текущего и желаемого поведения и включите соответствующие части кода в свой вопрос. Также, пожалуйста, задавайте только один вопрос за раз. Мне также нужна эта таблица, чтобы иметь полный контроль на стороне сервера для сортировки и разбивки на страницы - это совершенно другой новый вопрос.   -  person trixn    schedule 10.03.2020
comment
главный вопрос отредактировал, спасибо   -  person Jordan    schedule 10.03.2020
comment
Обновления состояния являются асинхронными. Вам они видны только во время следующего рендера. Вы не сможете увидеть измененное состояние, если console.log сразу после вызова setState().   -  person trixn    schedule 10.03.2020
comment
Я почти уверен, что здесь дело обстоит не так. Я попытался создать console.log внутри useEffect, который срабатывает при изменении состояния isOpen. но кажется, что он срабатывает только один раз от ложного до истинного, и это все   -  person Jordan    schedule 11.03.2020
comment
Обновления состояния, по крайней мере, если они вызываются в обработчике, являются асинхронными. Это факт. Причина, по которой это не работает: а) вы не добавили isOpen как зависимость от вашего обратного вызова. Он никогда не будет реконструирован и всегда будет setIsOpen(!false), потому что false был значением, когда он был впервые создан, и б) вы создаете компонент с обработчиком, который вы храните в состоянии в useEffect, который также вызывается только при монтировании. Таким образом, ваш компонент никогда не меняется, включая прикрепленный к нему обработчик. Также не стоит сохранять элементы в состоянии. Состояние должно состоять из простых данных.   -  person trixn    schedule 11.03.2020


Ответы (1)


Измените свой вызов setIsOpen на:

const handleClick = useCallback(() => setIsOpen(current => !current), []);

Изменить положение действий тестирования таблицы материалов и выход 2

Это решит эту проблему. Но все же не рекомендуется хранить в состоянии реагирующие элементы. Он должен содержать только простые данные, которые вы используете для визуализации фактических элементов.

person trixn    schedule 11.03.2020
comment
Большое спасибо за объяснение и предоставленное решение. к сожалению, я не уверен, как решить часть обработчиков, которые генерируются только один раз в useEffect. Если вы не против взглянуть на эту песочницу: codeandbox.io/s/server -generated-mt-ooc3e проблема в том, что когда я использую измененное состояние для запуска useEffect, это происходит слишком медленно. - person Jordan; 11.03.2020