Maria Jane Maria Jane - 2 months ago 15
React JSX Question

confusion between props and state in react.js

I followed a tutorial and came out with this https://jsbin.com/foxoxejilu/1/edit?js,output using react.js.

I'm confused with the props and state. In the

save
method of
Note component
, what does this line do

this.props.onChange(this.refs.newText.value, this.props.id)


And I don't see onChange and onRemove function elsewhere in the code, is that a pre-build function of react? how does react know the DOM got changed or removed?

Answer

We could summarise what is happening like this:

A Parent (Board) packs her Child (Note) a bag (props) and puts a mobile phone (onChange) and says: if you want to tell me something just text me the message. Then after some time the Child thinks "let's text my parent" so the Child takes the phone out of his properties and texts the Parent: this.props.onChange("Thank you for sandwiches"). The Parent, then receives the message and saves it into her notebook (state): this.setState({notes})

This is where the child receives the properties (props):

<Note key={note.id}
      id={note.id}
      onChange={this.update}
      onRemove={this.remove}>
      {note.note}
 </Note>

When the above finds its way to the render() method of the Board component (via {this.state.notes.map(this.eachNote)}, it's like Board saying,

  • "Hey let's render the Note component and lets give it some properties (props)".
  • "Let's name one of this props onChange and when it is invoked by the Note later, let's execute my own method called update"
  • "Instaed of calling this prop onChange we could call it whatever we want, for example
    <Note ... fromParentWithLove={this.update}> ... </Note>, but let's call it onChange so that it is easier to follow our intentions."

Then, we can move to the child component - Note. Note is saying to itself:

  • "Wow, if someone clicks on Save button let's run my own save method:" <button onClick={this.save}>Save</button>
  • "Then, inside my save method let's invoke the onChange function given to me by my parent Board via props": this.props.onChange(this.refs.newText.value, this.props.id)"

For reference, below is the code copied from the JSBin:

var Note = React.createClass({
        getInitialState(){
            return {editing: false}
        },
        edit() {
            this.setState({editing: true})
        },
        save() {
            this.props.onChange(this.refs.newText.value, this.props.id)
            this.setState({editing: false})
        },
        remove() {
            this.props.onRemove(this.props.id)
        },
        renderForm() {
            return(
                <div className="note">
                    <textarea ref="newText"></textarea>
                    <button onClick={this.save}>Save</button>
                </div>
            )
        },
        renderDisplay() {
            return(
                <div className="note">
                    <p>{this.props.children}</p>
                    <span>
                        <button onClick={this.edit}>Edit</button>
                        <button onClick={this.remove}>X</button>
                    </span>
                </div>
            )
        },
        render() {
            return (this.state.editing) ? this.renderForm() : this.renderDisplay()
        }
    })

 var Board = React.createClass({
        propTypes: {
            count: function(props, propName) {
                if(typeof props[propName] !== 'number'){
                    return new Error('the count must be a number')
                }
            }
        },
        getInitialState() {
            return {
                notes: [
                {id:1, note:'Call boook'},
                {id:2, note:'Buy Something'},
                {id:3, note:'Wash Clothes'},
                {id:4, note:'Go Jogging'}
                ]
            }
        },
        update(newText, id){
            var notes = this.state.notes.map(
                note => (note.id !== id) ?
                    note:
                    {
                        ...note,
                        note:newText
                    }
            )
            this.setState({notes})
        },
        remove(id){
            var notes = this.state.notes.filter(note => note.id !== id)
            this.setState({notes})
        },
        eachNote(note) {
            return (<Note key={note.id}
                          id={note.id}
                          onChange={this.update}
                          onRemove={this.remove}>
                      {note.note}
                    </Note>)
        },
        render() {
            return (<div className='board'>
                       {this.state.notes.map(this.eachNote)}
                    </div>)
        }
    })

ReactDOM.render(<Board count={10}> </Board>, 
        document.getElementById('react-container'))