2016-09-20 97 views
-2

我有父組件和子組件(listView)。我的目標是將後端調度的數據從父母發送到孩子。我通過點擊按鈕來實現。問題在於,小孩在第二個父按鈕點擊後呈現。也許我的錯誤在componentWillReceiveProps通過組件反應傳輸數據

家長:

class Parent extends Component { 
    constructor(props) { 
     super(props); 
     this.state = { 
      dataSource: '', 
      noRepos: false 
     }; 
    } 

    componentWillReceiveProps(newProps) { 
     this.setState({ 
      dataSource: newProps.data 
     }); 
     this.validateData(newProps) 
    } 
    submitUsername() { 
     if(this.validateInput()){ 
      this.props.dispatch({type: 'DUMMY', state: this.state.username}); 
     } else { 
      this.setState({emptyInput: true}); 
     } 
    } 
    render() { 
     return (
      ... 
      <View> 
       <ListViewComponent dataRecieved={this.state.dataSource} /> 
      </View> 
      ... 
     ); 
    } 
} 

export default connect(state => { 
    return { 
     data: state.data, 
    }; 
})(Parent); 

兒童:

export default class ListViewComponent extends Component { 
    constructor(props) { 
     super(props); 
     this.state = { 
      dataSource: new ListView.DataSource({ 
       rowHasChanged: (r1, r2) => r1 !== r2, 
      }), 
     }; 
    } 

    propTypes: { 
     dataRecieved: PropTypes.func.string 
    }; 

    componentWillReceiveProps(newProps) { 
     this.setState({ 
      dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved), 
     }); 
    } 
    renderRow(rowData) { 
     return (
      <View> 
       <Text>{rowData.name}</Text> 
      </View> 
     ); 
    } 
    render() { 
     return (
      <View> 
       <ListView dataSource={this.state.dataSource} 
          enableEmptySections={true} 
          renderRow={this.renderRow} /> 
      </View> 
     ); 
    } 
} 
+0

錯誤是你的'ListViewComponent'的'componentWillReceiveProps'使用'this.props.dataReceived'而不是'newProps.dataReceived'。還請檢查您的拼寫,它應該是'Received',而不是'Recieved'。 – rclai

回答

1

好了,一般的建議是要始終保持真實性單一來源:

  • 不復制你已經讀過的數據你有道具到你的內部組件狀態。使用道具中的數據。

  • 嘗試創建儘可能無狀態的組件(請參閱上面的...使用道具,或讓組件聽取'store'。請參閱Redux或AltJs)。


具體來嘗試解決您的問題:

在父母代替:

<ListViewComponent dataRecieved={this.state.dataSource} /> 

<ListViewComponent dataRecieved={this.props.data} /> 

而且在ListViewComponent,不這樣做:

this.setState({ 
     dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved), 
    }); 

但做:

render() { 

    var ds = new ListView.DataSource({ 
        rowHasChanged: (r1, r2) => r1 !== r2, 
    }) 
    , dataSource = ds.cloneWithRows(this.props.dataRecieved); 

    return (
     <View> 
       <ListView dataSource={dataSource} 
      enableEmptySections={true} 
      renderRow={this.renderRow} /> 
     </View> 
    ); 
} 

以上是未經測試的代碼,而應該作爲一個指南,遵循什麼辦法。

+0

1.你看到數據拷貝的地方? 2舉例說明。你看這不是一個答案。這是一些指導 – TeodorKolev

+0

我認爲這顯然是數據被複制的地方。 I.E在'Parent' this.setState({dataSource:newProps.data}) – JorgeObregon

+0

這份拷貝或參考? – TeodorKolev

1

您最初實施的方式ListViewComponent沒問題,在刷新ListView時應該使用componentWillReceiveProps。每個最佳做法都表示要這樣做(只是Google react native redux listview)。您在上面的評論中提到的實施中存在輕微的錯誤。此外,你不應該render功能內重新創建ListView.DataSource,這是不利於性能和擊敗rowHasChangedListView.DataSource的目的。

,我說的是錯誤是在這裏:

componentWillReceiveProps(newProps) { 
    this.setState({ 
    dataSource: this.state.dataSource.cloneWithRows(this.props.dataRecieved), 
    }); 
} 

它應該是:

// ListViewComponent 
componentWillReceiveProps(newProps) { 
    this.setState({ 
    dataSource: this.state.dataSource.cloneWithRows(newProps.dataRecieved), 
    }); 
} 

此外,您Parent不應該持有它的state一個dataSource,只是通過data直接降至ListViewComponent,因爲Redux已將其作爲prop已經通過:

class Parent extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     // ... 
    }; 
    } 

    componentWillReceiveProps(newProps) { 
    // ... 
    } 

    submitUsername() { 
    if (this.validateInput()) { 
     this.props.dispatch({ type: 'DUMMY', ... }); 
    } else { 
     // ... 
    } 
    } 
    render() { 
    return (
     ... 
     <View> 
     {/* this.props.data automatically comes from the `connect` wrapper below */} 
     <ListViewComponent dataRecieved={this.props.data} /> 
     </View> 
     ... 
    ); 
    } 
} 

export default connect(state => { 
    return { 
    data: state.data, 
    }; 
})(Parent); 

您還應該看看gist。這是一個如何使用Redux以及ListView的例子。他的例子使用cloneWithRowsAndSections,但因爲你沒有章節,所以你只需改編cloneWithRows。這個要點是由一個非常活躍的核心React Native開發人員編寫的。