【问题标题】:Component not re-rendering after change in an array state in React反应,数组状态更改后组件不重新渲染
【发布时间】:2022-07-08 01:50:53
【问题描述】:

删除状态中的元素后组件不会重新渲染,但状态确实发生了变化。 在组件中,可以通过form在数组中添加一个元素(也就是一个状态),查看数组中的所有元素,并通过按钮将其从状态中删除。因此,在删除处于状态的元素后,组件不会重新渲染。以下是组件的代码:

import React, { useEffect, useState } from 'react';
import {
  Typography,
  IconButton,
  Button,
  TextField,
  Paper,
} from '@mui/material';
import {
  CancelOutlined,
  AddBoxOutlined,
  VisibilityOutlined,
  VisibilityOffOutlined,
} from '@mui/icons-material';

export default function Test1() {
  const [subNames, setSubNames] = useState([]);
  const [subName, setSubName] = useState('');
  const [showSubForm, setShowSubForm] = useState(false);

  const onSubNameChange = (e) => {
    setSubName(e.target.value);
  };

  const onSubNameSubmit = () => {
    if (!subName) return alert('Enter name!');

    setSubNames((prev) => prev.concat({ name: subName }));
    setShowSubForm(false);
    setSubName('');
  };

  const subForm = (
    <>
      <div
        sx={{
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}>
        <TextField
          label='Sub Todo Name'
          onChange={onSubNameChange}
          name='subTodoName'
          value={subName}
          size='small'
          variant='outlined'
          fullWidth
        />
        <IconButton onClick={onSubNameSubmit}>
          <AddBoxOutlined color='primary' />
        </IconButton>
      </div>
      <br />
    </>
  );

  const onDelete = (position, e) => {
    let arr = subNames;

    arr.splice(position, 1);

    setSubNames(arr);
  };

  return (
    <div>
      <h1>Hello World!</h1>
      {subNames.map((item, key) => (
        <Paper
          key={key}
          sx={{
            display: 'flex',
            justifyContent: 'space-between',
            alignItems: 'center',
            margin: 'auto',
            padding: 10,
            marginTop: 10,
            borderRadius: '10px',
          }}
          elevation={3}>
          <div sx={{ display: 'flex', alignItems: 'center' }}>
            <Typography variant='body1'>
              <b>Sub Todo-{key + 1}:</b>
            </Typography>
            &nbsp;
            <Typography variant='body1'>{item?.name}</Typography>
          </div>
          <IconButton onClick={(e) => onDelete(key, e)}>
            <CancelOutlined color='primary' />
          </IconButton>
        </Paper>
      ))}
      <br />
      {showSubForm && subForm}
      <div>
        {showSubForm && (
          <Button
            variant='contained'
            sx={{ float: 'right' }}
            color='primary'
            size='small'
            startIcon={<VisibilityOffOutlined />}
            onClick={() => setShowSubForm(false)}>
            Add sub todo item
          </Button>
        )}
        {!showSubForm && (
          <Button
            variant='contained'
            sx={{ float: 'right' }}
            onClick={() => setShowSubForm(true)}
            color='primary'
            size='small'
            startIcon={<VisibilityOutlined />}>
            Add sub todo item
          </Button>
        )}
      </div>
    </div>
  );
}

【问题讨论】:

    标签: javascript reactjs react-state


    【解决方案1】:

    React 不会重新渲染,因为它就像什么都没有改变,即每次你将相同的 state 提供给 setState 时。对于像 NumberStringBoolean 这样的原始值,很明显知道我们是否给出了不同的值。

    另一方面,对于ObjectArray 等引用值,更改它们的content 不会将它们标记为不同。应该是不同的内存reference。查看您的注释代码以了解您做错了什么:

    let arr = subNames;      // will do a reference copy => arr == subNames
    arr.splice(position, 1); // will change its content => arr == subNames
    setSubNames(arr);        // at this point it's like nothing has changed
    

    一个解决方案可能是spread operator,它将创建现有数组的副本但在新的内存引用上,就像这样(注意你可以避免使用这个arr中间变量):

    // changes the content of the array while keeping its memory reference
    subNames.splice(position, 1); 
    // the spread operator creates a copy on a new memory reference
    setSubNames([...subNames]); 
    

    【讨论】:

      猜你喜欢
      • 2017-03-24
      • 2021-01-27
      • 2020-01-13
      • 2020-10-07
      • 2019-04-03
      • 2021-06-20
      • 2022-07-12
      • 2020-05-04
      • 2023-03-22
      相关资源
      最近更新 更多