【问题标题】:React transfer data through componentsReact 通过组件传输数据
【发布时间】:2017-01-28 17:42:31
【问题描述】:

我有父组件和子(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>
        );
    }
}

【问题讨论】:

  • 错误是您的ListViewComponentcomponentWillReceiveProps 使用的是this.props.dataReceived 而不是newProps.dataReceived。另外请检查您的拼写,应该是Received,而不是Recieved

标签: javascript reactjs react-native react-redux


【解决方案1】:

好的,一般建议是始终保持单一的事实来源:

  • 不要将 props 中已有的数据复制到内部组件状态。使用 props 中的数据。

  • 尝试创建尽可能无状态的组件(参见上文...使用 props,或让组件监听“存储”。参见 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>
    );
}

以上是未经测试的代码,但应作为遵循何种方法的指南。

【讨论】:

  • 1.您在哪里看到数据副本? 2 举例。你看这不是一个答案。这是一些准则
  • 我认为复制数据的位置很明显。 IE in Parent this.setState({ dataSource: newProps.data })
  • 这是副本还是参考?
  • 它正在将 props 中的数据克隆到 state 中。
  • 如何避免?
【解决方案2】:

您最初实现ListViewComponent 的方式很好,刷新ListView 时应该使用componentWillReceiveProps。那里的每个最佳实践都说要这样做(只是谷歌react native redux listview)。我在上面的评论中提到的你的实现中只是有一个小错误。此外,您不应该render 函数中重新创建ListView.DataSource,这对性能不利,并且违背了ListView.DataSourcerowHasChanged 的目的。

我说的错误在这里:

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。这是一个如何在 ListView 旁边使用 Redux 的示例。他的示例使用cloneWithRowsAndSections,但由于您没有部分,因此您只需改用cloneWithRows。这个要点是由一位非常活跃的核心 React Native 开发人员编写的。

【讨论】:

    猜你喜欢
    • 2020-04-03
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 2018-11-11
    • 2017-04-28
    • 2020-05-21
    • 2016-12-09
    • 2020-03-13
    相关资源
    最近更新 更多