Как правильно управлять состоянием реакции для списка JSX.Elements

Я использую реактивные крючки для управления списком JSX.Elements. Однако после изменения элемента попытка его удаления приведет к неожиданному поведению.

Я пытался использовать useReducer, удалить по индексу и т. д., но все равно произошел неожиданный обновленный результат.

FolderPage.tsx

import React, { useState, useEffect } from 'react';
import { Button, Box, Grid } from 'grommet';
import { Add, Close } from 'grommet-icons';

import { Files } from '../Component/Files/Files';
import { ePub } from '../extension/ePub/ePub';

interface Props {}

export const FolderPage: React.FC<Props> = () => {
  const [state, setState] = useState([<Files openFileHandlers={[ePub]} />]);

  const newFolderPanel = () => setState(prev => prev.concat(<Files openFileHandlers={[ePub]} />));

  const removePanel = (panel: JSX.Element) => setState(prevState => prevState.filter(s => s !== panel));

  return (
    <div>
      <Box align="start" pad="xsmall">
        <Button icon={<Add />} label="New Folder Panel" onClick={newFolderPanel} primary />
      </Box>
      {state.map((s, index) => (
        <Grid key={index}>
          <Box align="end">
            <Button
              icon={<Close color="white" style={{ backgroundColor: 'red', borderRadius: '50%', padding: '.25rem' }} />}
              type="button"
              onClick={() => removePanel(s)}
            />
          </Box>
          {s}
        </Grid>
      ))}
    </div>
  );
};

Например, при использовании: введите здесь описание изображения

Что я должен изменить в своем коде, чтобы мой щелчок по удалению удалит соответствующий элемент?


person Jiahua Zhang    schedule 16.10.2019    source источник


Ответы (1)


Есть способ обойти это. Для каждого элемента внутри массива. Вместо того, чтобы хранить элемент напрямую, сохраните его как {id: yourAssignedNumber, content: item}.

Таким образом, вы можете контролировать идентификатор и удалять, сравнивая только идентификатор. Таким образом, он будет работать правильно.

import React, { useState, useRef } from 'react';
import { Button, Row, Col } from 'antd';

import { Files } from '../Components/Files/Files';
import { fileHandler } from '../model/fileHandler';

interface Props {
  fileHandlers?: fileHandler[];
}

export const FolderPage: React.FC<Props> = ({ fileHandlers }) => {
  const [state, setState] = useState([{ key: -1, content: <Files fileHandlers={fileHandlers} /> }]);
  const key = useRef(0);

  const newFolderPanel = () =>
    setState(prev =>
      prev.concat({
        key: key.current++,
        content: <Files fileHandlers={fileHandlers} />
      })
    );

  const removePanel = (key: number) => setState(prevState => prevState.filter(s => s.key !== key));

  return (
    <Row>
      <Button type="primary" icon="plus" onClick={newFolderPanel} style={{ margin: '.75rem' }}>
        New Foldr Panel
      </Button>
      {state.map(({ key, content }) => (
        <Col key={key}>
          <div
            style={{
              background: '#75ff8133',
              display: 'grid',
              justifyItems: 'end',
              padding: '.5rem 1rem'
            }}>
            <Button onClick={() => removePanel(key)} icon="close" type="danger" shape="circle" />
          </div>
          {content}
        </Col>
      ))}
    </Row>
  );
};
person Jiahua Zhang    schedule 30.10.2019