通过组件

时间:2016-09-20 17:19:40

标签: javascript reactjs react-native react-redux

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

2 个答案:

答案 0 :(得分:1)

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

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

  • 尝试尽可能无状态地创建您的组件(请参阅上文...使用道具,或让组件收听&#39;存储&#39;。请参阅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 :(得分:1)

您最初实施var wikipedia = require("node-wikipedia"); var infobox = require('wiki-infobox'); var Promise = require('es6-promise').Promise; var fs = require('fs'); String.prototype.format = function() { var content = this; for (var i=0; i < arguments.length; i++) { var replacement = '{' + i + '}'; content = content.replace(replacement, arguments[i]); } return content; }; function getLinks() { return new Promise(function(resolve, reject) { wikipedia.page.data("List_of_hip_hop_musicians", { content: true }, function(response) { fs.writeFile("response.json", JSON.stringify(response, null, 2), function(err) { if(err) { return console.log(err); } }); resolve(response.links); }); }); } function getInfo(links){ return new Promise(function(resolve, reject) { fs.appendFile("info.csv", "name, background, birth_name, birth_date, birth_place, origin, genre, occupation, instrument, years_active, label, website\n", function(err) { if(err) { return console.log(err); } }); for (i=0; i<10; i++) { var link = links[i]['*']; resolveInfo(link).then(function(newText){ fs.appendFile("info.csv", newText, function(err) { if(err) { return console.log(err); } }); }); } resolve(text) }); } function resolveInfo(link) { return new Promise(function(resolve, reject) { infobox(link, 'en', function(err, data){ if (err) { return console.log(err); } try { var text = '{0}, {1}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}\n'.format(data.name.value, data.background.value, data.birth_name.value, data.birth_date.value, JSON.stringify(data.birth_place), data.origin.value, data.genre.text, JSON.stringify(data.occupation), data.instrument.text, data.years_active.value, data.label.value, data.website.value); } catch(err){ var text = ""; } resolve(text); }); }); } getLinks().then(function(links) { getInfo(links).then(function(text){ }); }); 的方式很好,在刷新ListViewComponent时,您应该使用componentWillReceiveProps。那里的每一个最佳实践都说要做到这一点(只有Google ListView)。您在上面的评论中提到的实施中只是略有错误。此外,不应该重新创建react native redux listview函数中的ListView.DataSource,这对性能不利,并且在render中违背了rowHasChanged的目的}。

我所说的错误就在这里:

ListView.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中持有dataSource,只需将state直接传递到data,因为Redux会将其作为ListViewComponent传递给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);

ListView

您还应该看看这个gist。这是如何将Redux与cloneWithRowsAndSections一起使用的示例。他的示例使用cloneWithRows,但由于您没有部分,因此您只需使用public function Person_name($person_code) { $code= explode(',', $person_code); $name=array(); for($i=0; $i<count($code); $i++){ $sql= Yii::app()->db->createCommand('select nm_person from tbl_person where kd_person="'.$code[$i].'";'); $name=$sql->queryRow(); } $namearray= implode(',',$name); return $namaarray; } 进行调整。这个要点是由一个非常活跃的核心React Native开发人员编写的。