2014-10-24 4 views
0

Компонент Примеры получает данные (список примеров) из компонента определения. Поскольку эти примеры могут быть отредактированы пользователем, они помещаются в форму состояния, форма состояния также позволяет нам создавать/удалять дополнительные поля при каждом изменении состояния.setState триггеры реквизиты изменения

Состояние изменяется при каждом нажатии клавиши (функция handleChangeExample), но также кажется, что свойства (props.examples) также обновляются, и я не могу понять, почему он это делает.

Я считаю, что свойства компонента Примеры должны оставаться неизменными/неизменными в течение всего цикла, если мы явно не сохраним блок (функция saveBlock), который в свою очередь запускает функцию saveExamples из компонента parent-Definition.

var Examples = React.createClass({ 
    getInitialState: function() { 
     return { 
      examples: this.props.examples 
     } 
    }, 

    editBlock: function(event) { 
//  this.setState({examples: this.props.examples}); 
     this.setState({editingBlock: !this.state.editingBlock}); 
    }, 

    saveBlock: function(event) { 
     var that = this; 
     var filtered_examples = []; 

     this.state.examples.forEach(function(example) { 
      if (example !== '') { 
       filtered_examples.push(example); 
      } 
     }); 

     this.props.saveExamples(filtered_examples); 
    }, 

    handleChangeExample: function(i) { 
     var updated_examples = this.state.examples; 
     updated_examples[i] = this.refs['example_' + i].getDOMNode().value.trim(); 

     this.setState({examples: updated_examples}); 
    }, 

    render: function() { 
     var that = this; 
     var fields = {}; 

     console.log(this.props.examples); 
     console.log(this.state.examples); 

     this.state.examples.forEach(function(example, i) { 
      if (example !== '') { 
       fields['example-' + i] = 
        <li className='editing__entry'> 
         <input type='text' 
           key={i} 
           ref={'example_' + i} 
           onChange={that.handleChangeExample.bind(null, i)} 
           defaultValue={example} /> 
        </li>; 
      } 
     }); 

     fields['example-' + (this.state.examples.length+1)] = 
      <li className='editing__entry'> 
       <input type='text' 
         key={this.state.examples.length+1} 
         ref={'example_' + (this.state.examples.length+1)} 
         onChange={that.handleChangeExample.bind(null, (this.state.examples.length+1))} 
         defaultValue='' /> 
      </li>; 

     return (
      <section className='definition__examples block'> 
        <div className='editing'> 
         <ul className='editing__fields'> 
          {fields} 
         </ul> 
        </div> 
      <button onClick={this.saveBlock} className='button--primary--small'>Save changes</button> 

      </section> 
     ); 
    } 
}); 


var Definition = React.createClass({ 
    getInitialState: function() { 
     return { 
      examples: this.props.definition.examples 
     } 
    }, 

    saveExamples: function(examples) { 
     this.setState({examples: examples}); 
    }, 


    render: function() { 
     var editingMode = this.props.editingMode; 
     var object = this; 

     return (
      <li className='definition'> 
      <Examples editingMode={editingMode} 
         examples={this.state.examples} 
         saveExamples={this.saveExamples} /> 
      </li> 
     ); 
    } 
}); 

module.exports = Definition; 

ответ

1

Вы видите это поведение, потому что this.state.examples это просто ссылка на this.props.examples.

this.props.examples обновляется по той же причине, что это ожидаемое поведение в простом JavaScript:

> var a = [ 'abc', 'def', 'ghi' ]; 
undefined 
> a 
[ 'abc', 'def', 'ghi' ] 
> var b = a; 
undefined 
> b 
[ 'abc', 'def', 'ghi' ] 
> b[1] = 'DEF'; 
'DEF' 
> b 
[ 'abc', 'DEF', 'ghi' ] 
> a 
[ 'abc', 'DEF', 'ghi' ] 

Есть несколько способов обойти это. Одним из них является создание копии this.props.examples и установить, что в this.state.examples (вы можете сделать это с помощью Array.prototype.slice):

getInitialState: function() { 
    return { 
     examples: this.props.examples.slice() 
    } 
} 

Я думаю, что это будет работать в вашем случае, поскольку examples просто массив строк , Однако slice создаст только мелкую копию массива, поэтому, если элементы были объектами или массивами, вы все равно закончите обновление this.props.examples.

Другой вариант - использовать Immutability Helpers для обновления состояния. Вы также можете взглянуть на immutable-js.

Вот упрощенный пример, как сделать то, что вы пытаетесь сделать, но с помощниками по нерушимости: jsfiddle.

/** @jsx React.DOM */ 

var SomeComponent = React.createClass({ 

    getInitialState : function() { 
     return { 
      examples : this.props.examples, 
     } 
    }, 
    _handleChange : function(index, e) { 
     var updateObj = {}; 
     updateObj[ index ] = { $set : e.target.value }; 

     var newData = React.addons.update(this.state.examples, updateObj); 

     this.setState({ examples : newData }); 
    }, 

    render : function() { 
    return (
     <div> 
     <input onChange={this._handleChange.bind(this, 0)}/><br/> 
     <input onChange={this._handleChange.bind(this, 1)}/><br/> 
     props: 
     <pre>{JSON.stringify(this.props.examples,null,2)}</pre> 
     state: 
     <pre>{JSON.stringify(this.state.examples,null,2)}</pre> 
     </div> 
    ); 
    } 
}); 

React.renderComponent(<SomeComponent examples={ [ "ABC", "DEF" ] } />, document.getElementById('main')); 
Смежные вопросы