Home > database >  Component not re-rendering after change in an array state in react
Component not re-rendering after change in an array state in react

Time:02-20

The component is not rerendering after the deletion of an element in the state but the state does change. In the component, you can add an element in the array (which is a state) through form, see all the elements in the array, and delete it from the state using the button. So after deleting an element that is in the state, the component does not rerender. Following is the code of the component:

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>
  );
}

CodePudding user response:

React will not re-render, cause it is like nothing has changed, that is every time you give the same state to a setState. For primitive types like String, Boolean... it is obvious to know if we are giving different values or not. For reference types like Array, Object... in the other hand, changing their content don't flag them as different value for React. It should be a different reference.

As you are doing, you are giving the same memory reference to setSubNames.

 let arr = subNames; // will do just a reference copy -> arr==subNames

A solution could be the spread operator, will create a copy of your existing array but on a new memory reference, like so :

const onDelete = (position, e) => {
  let arr = subNames;
  arr.splice(position, 1);
  setSubNames([...arr]);
};
  • Related