JSON.stringfy(ArrayData) change is not being subscribed in UseEffect in Nextjs

Viewed 43
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
  faSearch,
  faAmbulance,
  faAnchor,
  faPlus,
  faFloppyDisk,
} from '@fortawesome/free-solid-svg-icons';
import {
  Input,
  Table,
  Button,
  Modal,
  ModalBody,
  ModalHeader,
  ModalFooter,
  FormGroup,
  Label,
  Col,
  Row,
} from 'reactstrap';
import { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
export default () => {
  const dispatch = useDispatch();
  //receive the value from api const annexItems = useSelector((state) => state.d03reducer.annexItem)

  //filter the value where aanexID===5 const inclusion = annexItems?.filter(annex => { return (annex.itemType === "IN" && annex.annexID === '5') });

  console.log('inclusion', inclusion);

  //for setting the value in input fields for dynamic inclusion
  const [inclustionValue, SetinclusionValue] = useState([]);

  //use for summin the inclusionvalue
  const [inclusionValueSum, SetinclusionValueSum] = useState(0);
  const inclusionHandleChange = (e) => {
    const { name, value } = e.target;

    console.log('value on handlechange', value);

    var inclusionItem = inclustionValue.find((va) => va.itemID === name);
    console.log('item', inclusionItem);
    if (inclusionItem?.itemID === name) {
      //  inclusionItem.itemID = name;
      if (value === '') {
        value = 0;
      } else {
        value = value;
      }
      inclusionItem.value = value;

      console.log('inclusionValue after Update', inclustionValue);
    } else {
      if (value === '') {
        value = 0;
      } else {
        value = value;
      }
      SetinclusionValue([...inclustionValue, { itemID: name, value: value }]);
    }

    console.log('inclusion value inside', inclustionValue);
    // return inclustionValue;
  };

  //this does not work when i update the existing value in the array but works when the array value get changed
  useEffect(() => {
    const Sum = inclustionValue.reduce((acumulator, object) => {
      return parseFloat(acumulator) + parseFloat(object.value);
    }, 0);

    SetinclusionValueSum(Sum);
    // console.log("i am being called");
    console.log('sum in useeffect', Sum);
    console.log('sum after set in inclusionSum', inclusionValueSum);
  }, [JSON.stringify(inclustionValue)]);
  console.log('inclusion value', inclustionValue);

  const [snumber, setSnumber] = useState(1);

  return (
    <div>
      <div className='form card col-xs-12 col-sm-12 col-md-12 col-lg-9 col-xxl-9'>
        <Col className='card-header'>Annex 5</Col>
        <div className='card'>
          <Col className='card-body'>
            <Col className='card'>
              <div className='card mt-2'>
                <div className='card-header'>Inclusion(IN)</div>
                <div className='card-body'>
                  <Table bordered>
                    <tbody>
                      {inclusion?.map((annexItem, index) => {
                        return (
                          <tr key={index}>
                            <td>{index + 1}</td>
                            <td>{annexItem.itemDescNep}</td>
                            <td>
                              <Input
                                type='text'
                                className='form-control'
                                name={annexItem.itemID}
                                onChange={inclusionHandleChange}
                              ></Input>
                            </td>
                          </tr>
                        );
                      })}
                      <tr>
                        <td>{inclusion?.length + 1}</td>
                        <td>Total:(1 to {inclusion?.length})</td>
                        <td>
                          <Input
                            type='text'
                            className='form-control'
                            value={inclusionValueSum}
                          ></Input>
                        </td>
                      </tr>
                    </tbody>
                  </Table>
                </div>
              </div>
            </Col>
          </Col>
        </div>
      </div>
    </div>
  );
};

when I change the value in input fields the value do reflect in handlechanger but useEffect get called only when there is change in array length. I want to use useEffect also when the inclustionValue Array value updated too

2 Answers

Try to change your inclusionHandleChange function like this:

const inclusionHandleChange = (e) => {
  const { name, value } = e.target;
  const newValue = value === '' ? 0 : value;

  var inclusionItem = inclustionValue.find((va) => va.itemID === name);
  if (inclusionItem) {
    // Update existing item
    inclustionValue.find((va) => va.itemID === name).value = newValue
    // Triggers data refresh
    SetinclusionValue([ ...inclustionValue ])
  } else {
    // Add new inclusion value
    SetinclusionValue([ ...inclustionValue, { itemID: name, value: newValue }]);
  }
};

React is not going to re-render after inclusionItem.value = value because no state or props updated their references. Instead you want to create a new array, just like you're doing below with SetinclusionValue([...inclustionValue, { itemID: name, value: value }]);

It is imperative to remove mutation from your state updates in React. Try something like:

const index = inclustionValue.findIndex((va) => va.itemID === name);
if (index !== -1) {
  SetinclusionValue([...inclustionValue.slice(0, index), {...inclustionValue[index], value: value || 0}, ...inclustionValue.slice(index+1)]);
}

Or maybe

SetinclusionValue(inclus =>
  inclus.map((inc, i) => i === index ? ({...inc, value: value === "" ? 0 : value}) : inc));
Related