Home > Mobile >  React | Adding and deleting object in React Hooks (useState)
React | Adding and deleting object in React Hooks (useState)

Time:07-05

How to push element inside useState array AND deleting said object in a dynamic matter using React hooks (useState)?

I'm most likely not googling this issue correctly, but after a lot of research I haven't figured out the issue here, so bare with me on this one.

The situation:

I have a wrapper JSX component which holds my React hook (useState). In this WrapperComponent I have the array state which holds the objects I loop over and generate the child components in the JSX code. I pass down my onChangeUpHandler which gets called every time I want to delete a child component from the array.

Wrapper component:

export const WrapperComponent = ({ component }) => {
 
  // ID for component
  const { odmParameter } = component;


  const [wrappedComponentsArray, setWrappedComponentsArray] = useState([]);

const deleteChildComponent = (uuid) => {

    // Logs to array "before" itsself
    console.log(wrappedComponentsArray);
    // Output: [{"uuid":"acc0d4c-165c-7d70-f8e-d745dd361b5"}, 
     {"uuid":"0ed3cc3-7cd-c647-25db-36ed78b5cbd8"]


    setWrappedComponentsArray(prevState => prevState.filter(item => item !== uuid));

   // After
    console.log(wrappedComponentsArray);
   // Output: [{"uuid":"acc0d4c-165c-7d70-f8e-d745dd361b5",{"uuid":"0ed3cc3- 
    7cd-c647-25db-36ed78b5cbd8"]

  };

const onChangeUpHandler = (event) => {
    const { value } = event;
    const { uuid } = event;

    switch (value) {
      case 'delete':
        // This method gets hit
        deleteChildComponent(uuid);
        break;
      default:
        break;
    }
  };

const addOnClick = () => {
    
    const objToAdd = {
      // Generate uuid for each component
      uuid: uuid(),
      onChangeOut: onChangeUpHandler,
    };

    setWrappedComponentsArray(wrappedComponentsArray => [...wrappedComponentsArray, objToAdd]);

    // Have also tried this solution with no success
    // setWrappedComponentsArray(wrappedComponentsArray.concat(objToAdd));
  };

  return (
    <>
      <div className='page-content'>
        {/*Loop over useState array*/}
        {
          wrappedComponentsArray.length > 0 &&
          <div>
            {wrappedComponentsArray.map((props) => {
              return <div className={'page-item'}>
                <ChildComponent {...props} />
              </div>;
            })
            }
          </div>
        }
        {/*Add component btn*/}
        {wrappedComponentsArray.length > 0 &&
          <div className='page-button-container'>
            <ButtonContainer 
                             variant={'secondary'} 
                             label={'Add new component'}
                             onClick={() => addOnClick()}
           />
          </div>
        }
      </div>
    </>
  );


};

Child component:


export const ChildComponent = ({uuid, onChangeOut}) => {


  return (
    <>
      <div className={'row-box-item-wrapper'}>
        <div className='row-box-item-input-container row-box-item-header'>
          <Button
                props= {
                  type: 'delete',
                  info: 'Deletes the child component',
                  value: 'Delete',
                  uuid: uuid,
                  callback: onChangeOut
                }
              />
        </div>
       
        <div>
        {/* Displays generated uuid in the UI */}
        {uuid}
        </div>

      </div>
    </>
  )
}

As you can see in my UI my adding logic works as expected (code not showing that the first element in the UI are not showing the delete button):

enter image description here

Here is my problem though:

Say I hit the add button on my WrapperComponent three times and adds three objects in my wrappedComponentsArray gets rendered in the UI via my mapping in the JSX in the WrapperComponent.

Then I hit the delete button on the third component and hit the deleteChildComponent() funtion in my parent component, where I console.log my wrappedComponentsArray from my useState.

The problem then occurs because I get this log:

(2) [{…}, {…}]

even though I know the array has three elements in it, and does not contain the third (and therefore get an undefined, when I try to filter it out, via the UUID key.

How do I solve this issue? Hope my code and explanation makes sense, and sorry if this question has already been posted, which I suspect it has.

CodePudding user response:

You provided bad filter inside deleteChildComponent, rewrite to this:

 setWrappedComponentsArray(prevState => prevState.filter(item => item.uuid !== uuid));

You did item !== uuid, instead of item.uuid !== uuid

CodePudding user response:

Please try this, i hope this works

const deleteChildComponent = (uuid) => {
    console.log(wrappedComponentsArray);

    setWrappedComponentsArray(wrappedComponentsArray.filter(item => item !== uuid));
  };

After update

const deleteChildComponent = (uuid) => {
    console.log(wrappedComponentsArray);

    setWrappedComponentsArray(wrappedComponentsArray.filter(item => item.uuid !== uuid)); // item replaced to item.uuid
  };

CodePudding user response:

Huge shoutout to @Jay Vaghasiya for the help.

Thanks to his expertise we managed to find the solution.

First of, I wasn't passing the uuid reference properly. The correct was, when making the objects, and pushing them to the array, we passed the uuid like this:

 const addOnClick = () => {
      
      const objToAdd = {
        // Generate uuid for each component
        uuid: uuid(),
        parentOdmParameter: odmParameter,
        onChangeOut: function(el) { onChangeUpHandler(el, this.uuid)}
      };

      setWrappedComponentsArray([...wrappedComponentsArray, objToAdd]);
    };

When calling to delete function the function that worked for us, was the following:

const deleteChildComponent = (uuid) => {
    setWrappedComponentsArray(item => item.filter(__item => __item.uuid !== uuid)); // item replaced to item.uuid
  };
  • Related