FluentUI DetailsList onColumnClick с хуками React дает пустые элементы

Я пытаюсь создать DetailsList с сортируемыми столбцами (аналогично примеру в документации здесь: https://uifabric.azurewebsites.net/), но вместо компонента Class я хочу использовать функциональные компоненты и крючки.

Проблема в том, что когда выполняется функция onColumnClick, массив "items" все еще пуст.

Это в основном настройка моего компонента:

const MyList= () => {
  const [items, setItems] = useState([]);
  const [columns, setColumns] = useState([]);

  useEffect(() => {
    const newItems = someFetchFunction()
    setItems(newItems);

    const newColumns= [
      {
        key: "column1",
        name: "Name",
        fieldName: "name",
        onColumnClick: handleColumnClick,
      },
      {
        key: "column2",
        name: "Age",
        fieldName: "age",
        onColumnClick: handleColumnClick,
      },
    ];
    setColumns(newColumns);
  }, []);

  const handleColumnClick = (ev, column) => {
    console.log(items); // This returns [] instead of a populated array.
  };

  return <DetailsList items={items} columns={columns} />;
};

Проблема в том, что в handleColumnClick то itemsвозвращает пустой массив. Это очевидная проблема, когда вы хотите отсортировать элементы по определенному столбцу.

3 ответа

Я предполагаю, что причина, по которой массив элементов пуст, заключается в том, что состояние было "украдено", ознакомьтесь с этой статьей: https://css-tricks.com/dealing-with-stale-props-and-states-in-reacts-functional-components/

Если честно, не понимаю, почему так происходит, наверное, onColumnClick обрабатывается асинхронно?!

Однако добавление useRef крючок решает проблему для меня:

const MyList = () => {
  const [columns, setColumns] = useState([]);
  const [items, setItems] = useState([]);
  const refItems = useRef(items);

  const updateItems = (newItems) => {
    refItems.current = newItems;
    setItems(newItems);
  }

  useEffect(() => {
    const newItems = someFetchFunction()
    updateItems(newItems);

    const newColumns = // ...
    setColumns(newColumns);
  }, []);

  const handleColumnClick = (ev, column) => {
    console.log(refItems.current);
  };

  return <DetailsList items={items} columns={columns} />;
};

Это связано с тем, что столбцы создаются только в useEffect один раз, и ваши элементы состояния закрываются внутри этого экземпляра метода onColumnClick. Следующий рендер создает новый экземпляр onColumnClick, но все столбцы имеют старый экземпляр с закрытыми старыми переменными. Простое решение для этого состоит в том, чтобы добавить в свой код при каждом рендеринге (то есть непосредственно в функции компонента) что-то вроде этого:

      columns.forEach(c => c.onColumnClick = _onColumnClick); 

чтобы повторно прикрепить текущий _onColumnClick ко всем столбцам.

Здесь проблема связана сclosures. Ваш столбец является закрытием компонента (функции) MyList и фиксирует состояние переменной во время ее создания.

У useEffect пустой массив зависимостей, поэтому он запускается только один раз, присваивая функцию свойству onColumnClick с пустымitemмассив - кажется, что он пуст при первом запуске.

Решением в вашем случае может быть перемещение вашей переменной за пределы хука useEffect, так что обаhandleColumnClickиnewItemsиметь один и тот же экземпляр на каждом рендере, например:

      const [items, setItems] = useState([]);

useEffect(() => {
    const newItems = someFetchFunction()
    setItems(newItems);
}, []);

const handleColumnClick = (ev, column) => {
    console.log(items);
};

const newColumns = [
    {
        key: "column1",
        name: "Name",
        fieldName: "name",
        onColumnClick: handleColumnClick,
    },
    {
        key: "column2",
        name: "Age",
        fieldName: "age",
        onColumnClick: handleColumnClick,
    },
];

return <DetailsList items={items} columns={newColumns} />;

Если вам не нравится идея воссозданияnewColumnsпри каждом повторном рендеринге вы также можете добавить второй useEffect с[items]зависимость для запуска только послеitemsв конечном итоге доступен в состоянии компонентов.

Другие вопросы по тегам