score:2

Accepted answer

this is how javascript works with objects. they are always passed by reference and the others (strings, booleans, numbers as you mentioned) are primitives meaning they are immutable.

there are many amazing answers on so already regarding these:

  1. javascript by reference vs. by value
  2. is javascript a pass-by-reference or pass-by-value language?

how do we get around this?

in your snippet, where you say data['name'] = e.target.value you are still mutating the state object, which is surely a not to do in react. you can read upon power of not mutating content in react docs.

you could create a copy of the test2 and choose to mutate that instead:

const data = {...this.state.test2};
data['name'] = e.target.value

but there is a chance that this function gets called programatically, this will run into an error because setstate is async. instead it gives us a functional version to deal with:

this.setstate(prevstate => ({
  test2: {
    ...prevstate.test2,
    name: value,
  }
}));

full demo:

class child extends react.component{
    constructor(props){
        super(props)
        this.state={
            test2: this.props.data,
            
        }
        this.changetextfield = this.changetextfield.bind(this)
    }
    changetextfield(e){
        const value = e.target.value
        this.setstate(prevstate => ({
          test2: {
            ...prevstate.test2,
            name: value,
          }
        }))
    }
    render(){           
        return(
            <div> 
                <input type="text" value={this.state.test2['name']} onchange={this.changetextfield}/>                                  
            </div>  
        )
    }
}

class parent extends react.component{
    constructor(props){
        super(props)
        this.state={
            test: {name: "hola"},
            editing: false,
        }
        this.edit = this.edit.bind(this)
        this.cancel = this.cancel.bind(this)
    }
    edit(){
        this.setstate({editing: true})
    }
    cancel(){
        this.setstate({editing: false})
    }
    render(){        
        return(
            <div>
                {(this.state.editing) ?
                     <react.fragment>
                        <child data={this.state.test}/>   
                        <button onclick={this.cancel}>cancelar</button>
                    </react.fragment>   
                :
                    <react.fragment>
                        <h1>{this.state.test['name']}</h1>
                        <button onclick={this.edit}>edit</button>   
                    </react.fragment>
                }
            </div>
        )
    }
}

$(document).ready(function(){
    reactdom.render(<parent/>, document.getelementbyid("app"))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>document</title>

    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> 
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>  
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    
   
</head>
<body>
    <div id="app"></div>
    <script src="parent.jsx" type="text/babel"></script>
</body>
</html>


Related Query

More Query from same tag