React usestate обновляется дважды при нажатии кнопки

#javascript #reactjs #use-state

#javascript #reactjs #use-state

Вопрос:

У меня есть выпадающий список, который появляется при нажатии кнопки внутри таблицы react.

   function Table({ columns, data, getTrProps, isShowing }) {
  const [isVisible, setIsVisible] = useState(false);
  const currentColOrder = React.useRef();
  const { store } = useContext(AppContext);

  const handleChange = () => {
    setIsVisible(() => !isVisible);
  };

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
    allColumns,
    visibleColumns,
    setColumnOrder,
    getToggleHideAllColumnsProps,
  } = useTable(
    {
      columns,
      data,
    },
    useSortBy,
    useRowSelect,
    useColumnOrder,

    hooks => {
      hooks.visibleColumns.push(columns => [
        {
          id: 'selection',
          className: 'selection',
          disableSortBy: true,
          accessor: '',

          Header: ({ getToggleAllRowsSelectedProps }) => (
            <div>
              <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
            </div>
          ),

          Cell: ({ row }) => (
            <div>
              <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
            </div>
          ),
        },
        ...columns,
        {
          className: 'Columns_Menu',
          disableSortBy: true,
          id: 'Eye',
          Header: () => (
            <StyledEyeButton type="button" onClick={handleChange} id="eye">
              <Eye />
            </StyledEyeButton>
          ),

          Cell: () => <div />,
        },
      ]);
    },
  );

  return (
    <>
      <StyledTable {...getTableProps()} isShowing={isShowing}>
        <thead>
          {headerGroups.map(headerGroup => (
            <DragDropContext
              onDragStart={() => {
                currentColOrder.current = visibleColumns.map(o => o.id);
              }}
              onDragUpdate={dragUpdateObj => {
                const colOrder = [...currentColOrder.current];
                const sIndex = dragUpdateObj.source.index;
                const dIndex = dragUpdateObj.destination amp;amp; dragUpdateObj.destination.index;

                if (typeof sIndex === 'number' amp;amp; typeof dIndex === 'number') {
                  colOrder.splice(sIndex, 1);
                  colOrder.splice(dIndex, 0, dragUpdateObj.draggableId);
                  setColumnOrder(colOrder);
                }
              }}
              key={1}
            >
              <Droppable droppableId="droppable" direction="horizontal">
                {droppableProvided => (
                  <tr {...headerGroup.getHeaderGroupProps()} ref={droppableProvided.innerRef}>
                    {headerGroup.headers.map((column, index) => (
                      <Draggable
                        key={column.id}
                        draggableId={column.id}
                        index={index}
                        isDragDisabled={!column.accessor}
                      >
                        {(provided, snapshot) => {
                          return (
                            <StyledTh {...column.getHeaderProps(column.getSortByToggleProps())}>
                              <div {...column.getHeaderProps()}>
                                <div
                                  {...provided.draggableProps}
                                  {...provided.dragHandleProps}
                                  ref={provided.innerRef}
                                  style={{
                                    ...getItemStyle(snapshot, provided.draggableProps.style),
                                  }}
                                >
                                  <StyledHeader className="header">
                                    {column.render('Header')}
                                    {column.id === 'selection' || column.id === 'Eye' ? (
                                      ''
                                    ) : column.isSorted ? (
                                      column.isSortedDesc ? (
                                        <UpChevron />
                                      ) : (
                                        <DownChevron />
                                      )
                                    ) : (
                                      <DownChevron />
                                    )}
                                  </StyledHeader>
                                </div>
                              </div>
                            </StyledTh>
                          );
                        }}
                      </Draggable>
                    ))}
                  </tr>
                )}
              </Droppable>
            </DragDropContext>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map(row => {
            prepareRow(row);

            return (
              <StyledTr {...row.getRowProps()} data-testid="row">
                {store?.get?.isLoadingSearchButton || store?.get?.isLoadingApplyButton
                  ? row.cells.map(cell => {
                      return (
                        <StyledTd
                          {...cell.getCellProps()}
                          {...getTrProps(cell)}
                          className={cell.column.className}
                        >
                          <Skeleton width="50%" />
                        </StyledTd>
                      );
                    })
                  : row.cells.map(cell => {
                      return (
                        <StyledTd
                          {...cell.getCellProps()}
                          {...getTrProps(cell)}
                          className={cell.column.className}
                        >
                          {cell.render('Cell')}
                        </StyledTd>
                      );
                    })}
              </StyledTr>
            );
          })}
        </tbody>
      </StyledTable>
      {isVisible ? (
        <DropDownTableMenu
          setIsVisible={setIsVisible}
          allColumns={allColumns}
          getToggleHideAllColumnsProps={getToggleHideAllColumnsProps}
          isVisible={isVisible}
        />
      ) : (
        <></>
      )}
    </>
  );
}
 

Изначально значение isVisible равно false. Когда я нажимаю на StyledEyeButton выпадающий список, он открывается, как и должен, и isVisible значение изменяется на true.

Однако, когда я снова нажимаю на кнопку, чтобы закрыть выпадающий список, значение для isVisible переключается на false, а затем переключается во второй раз обратно на true, так что выпадающий список никогда не закрывается.

У меня есть функция on outside click, которая передается в выпадающий список в таблице, и когда вы нажимаете вне выпадающего списка, она закрывается нормально, но проблема возникает только тогда, когда вы пытаетесь нажать кнопку eye, чтобы закрыть выпадающий список после открытия.

Я думал, что использование анонимной функции в handleChange должно было решить проблему, но это не так. Есть идеи, что является причиной этого? Единственное, о чем я могу думать, это то, что сама кнопка визуализируется из функции, и это вызывает проблему с состоянием, но я не был уверен, потому что кнопка не должна повторно визуализироваться после начальной загрузки.

Комментарии:

1. Не могли бы вы поделиться своим полным кодом? В настоящее время я не могу найти никакого использования isVisible в вашем коде.

2. Да, есть целая функция таблицы, раскрывающийся список show находится внизу функции @fi

3. Вероятно, проблема вызвана внешним щелчком. Когда вы нажимаете на выпадающий список, он запускает оба — выпадающий щелчок и внешний щелчок. Вы можете решить эту проблему, используя этот stopPropagation метод.

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

5. как выглядит ваш внешний щелчок? Я думаю, что проблема заключается в вашем внешнем клике