0

I have a React state that has some objects in it. I want to be able to clone the c: "value", in the initial state, before it gets overwritten by e.target.value input value

The reason why im doing this is because I want to this stored value to be tha actual value if user leaves the input empty

StateObj = {
 a: "one",
 b: 2,
 option: {
  c: "value"
 }
}
<InputComp 
 value={StateObj.option.c}
 onBlur={(e) => {
  if(e.target.value === ""){
    props.onChange(["option", "c"], "cloned value")} //the initial value c: "value"
   }
 }}
 onChange={(e) => props.onChange(["option", "c"], e.target.value)} //gets overwritten if user start typing
>
Plvtinum
  • 187
  • 1
  • 5
  • 11
  • What do you mean by reset the input, wouldn't it already be empty? – SuspenseFallback Jul 31 '23 at 00:02
  • sorry for the confusion, I meant to reset it back to that cloned c value – Plvtinum Jul 31 '23 at 00:16
  • For avoid referencing, I usually used spread syntax, "..." expression. – Humanoid Mk.12 Jul 31 '23 at 00:30
  • I did & the value still changes when u type on the input, I want this value to only get that initial value and prevent it from changing when the state changes. – Plvtinum Jul 31 '23 at 00:34
  • @HumanoidMk.12 he has nested objects and `...` does not deep copy. In a handful of cases you are right though. You would need to do something like this to perform a deep copy `JSON.parse(JSON.stringify(StateObj.option))`. – PCDSandwichMan Jul 31 '23 at 01:06

2 Answers2

3

Follow up to my comment on the OP.

Here is an example:

import React, { useState, useEffect, useRef } from 'react';

function YourComponent(props) {
  const [stateObj, setStateObj] = useState({
    a: "one",
    b: 2,
    option: {
      c: "value",
    },
  });

  const originalOption = useRef(null); // this will hold the original option object

  useEffect(() => {
    // On mount, store the initial value of the option object
    originalOption.current = JSON.parse(JSON.stringify(stateObj.option));
  }, []);

  const handleChange = (path, value) => {
    // your existing logic here to change the value
    if(value === '') {
      // if the input is emptied, reset the option object
      setStateObj(prevState => ({
        ...prevState,
        option: originalOption.current
      }));
    } else {
      // if there's a value, update the state normally
      // your logic here
    }
  };

  return (
    <InputComp
      value={stateObj.option.c}
      onChange={(e) => handleChange(["option", "c"], e.target.value)}
    />
  );
}

I highly suggest reviewing this post as well.

What is the most efficient way to deep clone an object in JavaScript?

PCDSandwichMan
  • 1,964
  • 1
  • 12
  • 23
2

To clone an object without referencing it, you can use the spread operator (...) or the Object.assign() method to create a shallow copy of the object. This way, any changes made to the cloned object won't affect the original one. Here's how you can achieve this in your React component:

Using the spread operator:

const clonedOption = { ...StateObj.option };

// Pass the cloned option to the InputComp
<InputComp 
  value={clonedOption.c}
  onChange={(e) => props.onChange(["option", "c"], e.target.value)}
>

Using Object.assign():

const clonedOption = Object.assign({}, StateObj.option);

// Pass the cloned option to the InputComp
<InputComp 
  value={clonedOption.c}
  onChange={(e) => props.onChange(["option", "c"], e.target.value)}
>

Both of these methods will create a new object, clonedOption, which is a shallow copy of StateObj.option. Changes made to clonedOption won't be reflected in the original object StateObj.option.

This way, you can safely use the clonedOption as the value for your input field, and when the user leaves the input empty, you can reset the input to the original value if needed.

SWS-5007
  • 26
  • 2
  • both the Object.assing nor the spread ... didnt work for me, it seems like value is still somehow referecing the state, but the assigning state to a useRef in a useEffect worked for me – Plvtinum Jul 31 '23 at 10:07