-1

I have two text boxes with id set dynamically as en which can change. Every time the onchange is emittted from input field, the state should update. The problem is, if I type something into one of the inputs, the other input state seems to disappear. For example, If I type test into title text field, the state becomes:

this.state = {
            translation: {
                en: {
                    title: 'test'
                }
            }
        };

If I move on to typing into the content text box, it seems to replace the title state. like so,

this.state = {
            translation: {
                en: {
                    content: 'content'
                }
            }
        };

They should update the state independently without affecting each other. Here is my intended state

this.state = {
            translation: {
                en: {
                    title: 'title-text',
                    content: 'content-text'
                }
            }
        };

Component

import React from 'react';

export default class Demo extends React.Component
{
    constructor(props)
    {
        super(props);

        // default state
        this.state = {
            translation: {}
        };
    }

    onSubmit(e)
    {
        e.preventDefault();
        console.log(this.state);
    }

    render()
    {
        return (

            <form onSubmit={(event) => this.onSubmit(event)}>

                    <input id="en" name="title"
                           onChange={(event) => this.setState({
                               translation: {
                                   [event.target.id]: {
                                     title: event.target.value
                                   }
                               }
                   })} />

                    <input id="en" name="content"
                              onChange={(event) => this.setState({
                                  translation: {
                                      [event.target.id]: {
                                          content: event.target.value
                                      }
                                  }
                      })} />

                    <button type="submit">Login</button>


            </form>

        );
    }
}
anonym
  • 4,460
  • 12
  • 45
  • 75
  • Possible duplicate of [this.setState isn't merging states as I would expect](https://stackoverflow.com/questions/18933985/this-setstate-isnt-merging-states-as-i-would-expect) – Ori Drori Jul 12 '17 at 10:25

4 Answers4

3

setState does not deeply merge current state and updates. You should spread your translation state prop.

this.setState({
  translation: {
    ...this.state.translation,
    [event.target.id]: {
      content: event.target.value
    }
  }
})
Ivan Burnaev
  • 2,690
  • 18
  • 27
1

The behaviour is correct.

   e.g: var obj = {a:1,b:3};
            obj = {a:4};//Obj updated. Now obj.b will be undefined.This is what you worried for.

In your case, you can do something like this. It is not one of the best solution.

onSubmit(e)
    {
        e.preventDefault();
        let state = this.state.translation;
        state.en.content =  'content';
        this.setState(state);

        console.log(this.state);
    }
Ved
  • 11,837
  • 5
  • 42
  • 60
1

As was mentioned, setState doesn't deeply merge values, however what you really need is to do is this:

this.setState({
  translation: {
    [event.target.id]: {
      ...this.state.translation[event.target.id],
      content: event.target.value
    }
})

And same for title.

Oliver Rydzi
  • 334
  • 1
  • 11
  • 1
    No problem. Generally speaking, you should deal with changes like that before submitting form (Regarding Ved's answer). – Oliver Rydzi Jul 12 '17 at 10:53
0

You forgot about immutability. Just add to your code ...this.state for import all the properties that have been there before.

this.state = {
  ...this.state,
..
}
Sergey
  • 7,184
  • 13
  • 42
  • 85