简体   繁体   中英

React onChange to handle state objects

I have an interesting question regarding React state and onChange events in the form. In my React component, I am storing information in the state, that includes objects. When a user types in a change, I would like part of that object in the state to change. As an example, here is the state I am talking about:

this.state = {
      total: 0,
      email: '',
      creditCards: [],
      selectedCreditCard: {},
      billingAddresses: [],
      shippingAddresses: [],
      selectedBillingAddress: {},
      selectedShippingAddress: {},
    }

This is the state of the component, and this is my handle change function:

  handleChange(event) {
    this.setState({
      [event.target.name]: event.target.value,
    })
  }

As you can probably tell, this type of function will not work for objects within the state. As an example, when a user types in their credit card number, I would like this.state.selectedCreditCard.creditCardNumber to be the thing that changes. Of course, with the way it is setup in my form:

<input
          type="text"
          name="selectedCreditCard.creditCardNumber"
          value={selectedCreditCard.creditCardNumber}
          onChange={(evt) => handleChange(evt)}
        />

The "name" being passed into the onChange is only a string, and not a pointer to a key value in one of the objects in the state. Therefore, there is no easy way for this function to work except for deconstructing each object in the state and placing every key:value directly in the state instead of within the object; doing this is a possibility, but the code becomes very cumbersome this way. I hope all of this makes sense. Is there any way to manipulate the objects within the state, and have the form pass a pointer to a key in the object, as opposed to a string? Thanks.

I understand from your description that you wish to update a nested child inside a state object attribute like below

//default state
this.state = {
      total: 0,
      email: '',
      creditCards: [],
      selectedCreditCard: {},
      billingAddresses: [],
      shippingAddresses: [],
      selectedBillingAddress: {},
      selectedShippingAddress: {},
    }

to be updated to something like this

//state after handleEvent
{
      total: 0,
      email: '',
      creditCards: [],
      selectedCreditCard:{
       creditCardNumber:"102131313"
      }, 
      billingAddresses: [],
      shippingAddresses: [],
      selectedBillingAddress: {},
      selectedShippingAddress: {},
 }

If thats the case. Here's a recursion based solution to create a nested object using a "." based name string.

  handleChange(event) {
    //use split function to create hierarchy. example:
    //selectedCreditCard.creditCardNumber -> [selectedCreditCard , creditCardNumber]
    const obj = this.generate(
      event.target.name.split("."),
      event.target.value,
      0
    );
    
    this.setState({ ...obj });
  }

  //use recursion to generate nested object. example
  //([selectedCreditCard , creditCardNumber] , 12 , 0) -> {"selectedCreditCard":{"creditCardNumber":"12"}} 
  generate(arr, value, index) {
    return {
      [arr[index]]:
        index === arr.length - 1 ? value : this.generate(arr, value, index + 1)
    };
  }

I have created a codesandbox demo for you to explore more here. demo-link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM