1
class CreateEventForm extends Component {
  constructor(props) {
    super(props)
    this.state = {
      fields: {
        name: '',
        location: '',
        description: '',
        datetime: '',
      },
      friendsInEvent: [],
    },
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    const { checked, value } = e.target
    let { friendsInEvent } = { ...this.state }
    if (checked) {
      friendsInEvent = [...friendsInEvent, value]
    } else {
      friendsInEvent = friendsInEvent.filter(el => el !== value)
    }
    this.setState({ friendsInEvent }, () => console.log(this.state))
  }

  render() {

    const { friends, createEvent, addFriendsToEvent } = this.props
    const { fields: { name, location, description, datetime } } = this.state

    const setter = propName => event => {
      const nextFields = { ...this.state.fields }
      nextFields[propName] = event.target.value
      this.setState({ fields: nextFields })
    }

    return (
      <div {...cssForm}>
        <div>
          <Label label="Event Name" />
          <Field onChange={setter('name')} />

          <Label label="Event Date/Time" />
          <Field onChange={setter('datetime')} type="datetime-local" />

          <Label label="Event Location" />
          <Field onChange={setter('location')} />

          <Label label="Event Description" />
          <Field onChange={setter('description')} />

            <SubHeader title="Add Friends to the Event..." />
              <div>
                {friends
                  .mapEntries(([friendId, frn]) => [
                    friendId,
                    <div key={friendId}>
                      <input
                          value={friendId}
                          type='checkbox'
                          onChange={this.handleChange}
                          defaultChecked={false} />
                      {frn.firstName} {frn.lastName}
                    </div>,
                  ])
                  .toList()}
              </div>

            <Link to="/">
                <Button style="blue" name="Done" onClick={() => createEvent(this.state.fields)} />
            </Link>
        </div>
      </div>
    )
  }
}

export default CreateEventForm

This code above works and stores all of the correct values as expected. However I want to move friendsInEvent[ ] inside fields{ }. To look like:

super(props)
 this.state = {
  fields: {
    name: '',
    location: '',
    description: '',
    datetime: '',
    friendsInEvent: [],
  },   
},
  this.handleChange = this.handleChange.bind(this);
}

How can I achieve this? Everything I have tried breaks the handleChange(e) function or overwrites fields{ } with the friendsInEvent array.

I assume I have to change the values inside the handleChange(e) function after I move the array inside this.state.field?

Also, is there a way to merge my two functions setter and handleChange(e)? I kept them separate as they handle two different types (string and array).

Thanks.

2
  • When are you moving friendsInEvent in fields, is it done dynamically Commented Jan 30, 2018 at 12:53
  • Right, it's a State specific, that if you need to updated nexted properties, you should copy the whole object fields, update it and only after that use setState. Not sure what your setter does, but it's definitely a bad idea to create it on each render, what you actually do Commented Jan 30, 2018 at 12:54

2 Answers 2

1

From the looks of it you'll need to make the following changes to handleChange:

handleChange(e) {
  const { checked, value } = e.target;

  // Ensure that you're destructuring from fields
  let { friendsInEvent } = { ...this.state.fields };
  if (checked) {
    friendsInEvent = [...friendsInEvent, value];
  } else {
    friendsInEvent = friendsInEvent.filter(el => el !== value)
  }

  // You need to take a copy of state, and then supply a new copy
  // of the the fields property which takes a copy of the old fields
  // property, and overwrites the friendsInEvent with the new data
  this.setState({
    ...this.state,
    fields: {...this.state.fields, friendsInEvent }
  }, () => console.log(this.state));
}

Here's a small React-free example of how this would work.

Sign up to request clarification or add additional context in comments.

Comments

0

Why can't you do it in the below way.

handleChange(e) {
    const { checked, value } = e.target
    let { friendsInEvent } = { ...this.state }
    if (checked) {
      friendsInEvent = [...friendsInEvent, value]
    } else {
      friendsInEvent = friendsInEvent.filter(el => el !== value)
    }
    let object = {};
    object.name = this.state.name;
    object.location = this.state.location;
    object.description = this.state.description;
    object.datetime = this.state.datetime;
    object.friendsInEvent = friendsInEvent;
    this.setState({
        fields: object
    })
  }

Never do setState inside render. You are not suppose to do setState inside render. Event handlers should be handled before render method but not inside of render. Try avoiding doing setState inside render.

const setter = propName => event => {
      const nextFields = { ...this.state.fields }
      nextFields[propName] = event.target.value
      this.setState({ fields: nextFields })
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.