2016-12-24 7 views
0

私は、複数のWebアプリケーションで反応を伴うreduxを使用しました。現在、Reduxで最初のReact Nativeアプリを開発しています。ReactネイティブsetStateをコンポーネントリビジョンストアに更新

私は非常に奇妙な問題に遭遇しました。

私はストアを作成し、それを子コンポーネントとしてレンダリングするプロバイダコンポーネントに渡しました。 (反応型還元剤の基本的な使い方)

私は接続されたコンポーネントを持っています。ストアから受信したデータをナビゲータルートに渡し、navigator.push(ルート)を呼び出します。このルートのコンポーネントは、接続されたコンポーネントではありません。それは小道具を受け取り、は小道具をその状態に保管する。小道具は単にリテラルではなく、オブジェクト/配列です。 ユーザーの操作に応じて、このコンポーネントは状態をsetStateに更新します。 この操作は直接ストアを更新しています。

私は店舗から受け取ったコンポーネント状態の小道具をmatchStateToPropsに設定していませんか?その場合でも、setStateは別のコンポーネントで起こっています。店舗は単にそれ自体を更新すべきではありません。

私は混乱しています。助けてください。

(問題が明確か混乱していない場合は、私は私のコードから、関連するコードスニペットを追加します)

EDIT 1:

Here is a fiddle which conveys my problem

const intialState = { 
    0: { 
    orgId: 0, 
    peopleInfo: { 
     0 : { 
     pID: 0, 
     name: 'parent', 
     children: [ 
      { 
      userID: 1, 
      name: 'abc', 
      }, 
      { 
      userID: 2, 
      name: 'xyz', 
      }, 
     ] 
     } 
    } 
    } 
} 


function reducer (currentState, action) { 
    currentState = intialState; 
    console.log(currentState[0].peopleInfo[0]); // priniting the store every time an action is dispatched 
    // NO CHANGES TO THE STORE WHEN ACTION IS DISPATCHED 
    return currentState; 
} 


// Create Store 
var store = Redux.createStore(reducer); 

// action creator which will simply trigger the reducer 
function save(){ 
    return { 
    type: 'SAVE' 
    } 
} 

// Presentational Components (No state, only props and render) 
var OrgsContainer = React.createClass({ 
    render() { 
    return (
     <div> 
     <div> 
      <div>1. Open console first</div> 
      <div>2. Change parent name - no change in the name property for the record on the store </div> 
      <div>3. Change any child - it changes the property on the store even if there is no implementation in the reducer</div> 
     <br /> 
     </div> 
     <PeopleContainer people ={this.props.peopleInfo} saveAction = {this.props.save} /> 
     </div> 
    ) 
    } 
}) 

var PeopleContainer = React.createClass({ 
    componentWillMount(){ 
    console.log(this.props) 
    this.setState({ 
     currentChildren: this.props.people[0].children, 
     parentName: this.props.people[0].name 
    }) 
    }, 
    onChildChangeName(event,index){ 
    console.log(event.target.value,index); 

    var newChildrenArray = this.state.currentChildren; 
    newChildrenArray[index].name = event.target.value 
    this.setState({ 
     currentChildren: newChildrenArray 
    }) 
    this.props.saveAction(); 
    }, 
    onParentChangeName(event){ 

    this.setState({ 
     parentName: event.target.value, 
    }) 
    this.props.saveAction() 
    }, 
    render(){ 
    return (
     <div> 
     Parent Name : <input value={this.state.parentName} onChange={(event) => this.onParentChangeName(event)} /> 
     <div><br /></div> 
     {this.state.currentChildren.map((child, index) => { 
     return(<div key={index}> 
     Name : <input value={child.name} onChange={(event) => this.onChildChangeName(event,index)} /> <div><br /></div> 
     </div>) 
     })} 
     </div> 
    ) 
    } 

}) 

// Map state and dispatch to props 
function mapStateToProps (state) { 
    return { 
    peopleInfo: state[0].peopleInfo, 
    }; 
} 

function mapDispatchToProps (dispatch) { 
    return Redux.bindActionCreators({ 
    save: save, 
    }, dispatch); 
} 

// Container components (Pass props into presentational component) 
var OrgsContainer = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(OrgsContainer); 


// Top-Level Component 
var App = React.createClass({ 
    render: function() { 
    return (
     <div> 
     <h3>App</h3> 
     <OrgsContainer /> 
     </div> 
    ); 
    } 
}); 



// Render to DOM 
var Provider = ReactRedux.Provider; // Injects store into context of all descendents 
ReactDOM.render(
    <Provider store={store}> 
    <App /> 
    </Provider>, 
    document.getElementById('container') 
); 

だから、とは何の関係もありませんネイティブに反応する。

還元剤の構造は、私のアプリで持っているデータモデルを模倣しています。

フィドルで見ることができるように、私たちは、渡された小道具を州に設定してそこに変更することはできません。オブジェクト参照のために形成されるストアへのリンクがあることは明らかである。そのような参照を更新すると、ストアの更新が終了します。

あなたの小道具を州に設置しないことが良い習慣ですが、私のシナリオにはそれが必要です。今のところ私はObject.assign()を使って新しいオブジェクトを作成し、このオブジェクトを私のために働く状態で使用しています。

私はおそらくこれについて通知するreduxドキュメントで何かを逃してしまったでしょう。誰かが何かを見つけた場合、私はそれを知ってうれしいです。

しかし、私はまだこの奇妙な発見です。

+1

コードを入力してください – Junior

答えて

1

最終的に、あなたの問題の原因は、あなたのonChildChangeName方法では、ということです。

var newChildrenArray = this.state.currentChildren; 
newChildrenArray[index].name = event.target.value 

あなたの店も参照している同じ基礎となるオブジェクトのインスタンスを変異されています。

あなたはonChildChangeNameに次の行を追加することでこれを確認することができます

console.log(intialState[0].peopleInfo[0].children === newChildrenArray); // true 

解決方法1: 最も簡単な解決策は、あなたが最初に設定されているときに、データの深いコピーを作成することができるということです状態:例:

this.setState({ 
    currentChildren: _.cloneDeep(this.props.people[0].children), 
    parentName: this.props.people[0].name 
}) 

これにより、アレイに深いコピーが作成されるため、nまたは配列内の項目がinitialState(店舗)と同じデータを参照しているため、副作用の恐れなしに配列/オブジェクトを変更することができます。


解決方法2: 代替オプションは、最初の配列のシャローコピーを作成し、あなたは配列内のアイテムを変更する必要があるたびに新しいオブジェクトインスタンスを作成することを確保することです。例えば、最初のsetStateを呼び出すときに、あなたのコンポーネントの配列への変更はinitialStateによって参照されている場合には発生しないことを確実にするために、slice()を行うことで、新しい配列を作成する例:

this.setState({ 
    currentChildren: this.props.people[0].children.slice(), 
    parentName: this.props.people[0].name 
}) 

そしてonChildChangeNameで、あなたは、常に既存のインスタンスを変異のではなく、新しいインスタンスを作成して、例えば:

var newChildrenArray = this.state.currentChildren; 
newChildrenArray[index] = {...newChildrenArray[index], name: event.target.value} 

けれども、あなたのコンポーネントを構築するとして、彼らはクローンの任意の並べ替えを行わない/ Reduxのは、データの様々なインスタンスの周りに渡しているリアクト/コピー操作新しいレフェリーを使用していることを確認するこれらの問題を回避するには、自分で行う必要があります。

関連する問題