2016-09-20 66 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开发人员编写的。