Undefined
Undefined

Reputation: 1021

Object clone in react

I am making a simple react application which has some basic inputs like first name, last name etc..,

The state of the inputs are handled in context api like,

context.js

import React, { useState } from "react";

export const FormContext = React.createContext();

export function FormProvider({ children }) {
  const [formValue, setFormValue] = useState({
    basicDetails: {
      firstName: "",
      lastName: "",
      address: {
        city: "",
        zip: ""
      }
    }
  });

  return (
    <FormContext.Provider value={[formValue, setFormValue]}>
      {children}
    </FormContext.Provider>
  );
}

In basic details component fetching the context like,

  const [value, setValue] = React.useContext(FormContext);
  const { basicDetails } = value;

Here to make a copy of initial value of context, I have tried using spread operator like,

  const initialValue = { ...value };

And in handleSubmit function tried to get the initially copied value (i.e..,) initialValue but this is logging the values of latest changes.

Working example:

Edit React Functional Component (forked)

Requirement:

On click of the form submission, I am in the need to reset the form values with initial context data.

To achieve the resetting of values to initial data only I have tried spread operator { ...value } but I think I am wrong with the approach.

Even JSON.parse(JSON.stringify(value)) doen't work in this case..

Kindly anyone help me to achieve of setting the form value to initial context on submit.

Upvotes: 1

Views: 591

Answers (2)

Drew Reese
Drew Reese

Reputation: 202915

The other answer here seems sufficient. You could also save the initial field values in a React ref (const initialValue = React.useRef(value);) and access later as initialValue.current.

In reality you want your context to have more control over the context state. I suggest creating a reset function to include in the context that children can consume.

context.js

Factor out the initial state definition, provide a default context value, and pass the state and callbacks to the context value.

const initialFormState = {
  basicDetails: {
    firstName: "",
    lastName: "",
    address: {
      city: "",
      zip: "123"
    }
  }
};

export const FormContext = React.createContext({
  formValue: initialFormState,
  setFormValue: () => {},
  reset: () => {}
});

export function FormProvider({ children }) {
  const [formValue, setFormValue] = useState(initialFormState);

  const reset = () => setFormValue(initialFormState);

  return (
    <FormContext.Provider
      value={{ value: formValue, setValue: setFormValue, reset }}
    >
      {children}
    </FormContext.Provider>
  );
}

basicDetails.js

Consume and destructure the context value. Change the submit button to be of type="submit" so you can submit the form, and call reset in the submit handler to reset the form state.

const BasicDetails = () => {
  const {value, setValue, reset} = React.useContext(FormContext);
  const { basicDetails } = value;

  const handleInputChange = (event) => {
    const { name, value: val } = event.target;
    setValue((prev) => {
      const basicDetails = {
        ...prev.basicDetails,
        ...(value.basicDetails[name] !== undefined
          ? { [name]: val }
          : { address: { ...value.basicDetails.address, [name]: val } })
      };
      return { ...prev, basicDetails };
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    // Do what you need with the current form values
    console.log("Values", value);

    // Finally reset the form
    e.target.reset();
  };

  return (
    <div>
      <h1> Basic Details </h1>
      <form onSubmit={handleSubmit} onReset={reset}>
        <label htmlFor="firstName">First Name: </label>
        <input
          type="text"
          className="form-control"
          id="firstName"
          name="firstName"
          value={basicDetails.firstName}
          onChange={handleInputChange}
        />
        <br />
        <br />
        <label htmlFor="lastName">Last Name: </label>
        <input
          type="text"
          className="form-control"
          id="lastName"
          name="lastName"
          value={basicDetails.lastName}
          onChange={handleInputChange}
        />
        <br />
        <br />
        <label htmlFor="lastName">City: </label>
        <input
          type="text"
          id="city"
          name="city"
          value={basicDetails.address.city}
          onChange={handleInputChange}
        />
        <br />
        <br />
        <label htmlFor="lastName">Zip: </label>
        <input
          type="text"
          className="form-control"
          id="lastName"
          name="zip"
          value={basicDetails.address.zip}
          onChange={handleInputChange}
        />
        <br />
        <br />
        <button type="submit">
          Submit
        </button>
      </form>
    </div>
  );
};

Edit object-clone-in-react

Upvotes: 1

lam
lam

Reputation: 565

if you just want to keep the initialValue always as the first time value, you need to do it like

const initialValue = useMemo(() => value, []);

as your code, the function runs whenever the value changes, so the initialValue changes every time when the value changes

Upvotes: 1

Related Questions