如何避免reactjs中的键/ id问题,并使道具从父母传递给孩子?

时间:2016-06-03 23:03:52

标签: ruby-on-rails reactjs react-rails

在尝试将父数据传递给子组件时,我不断碰壁。

我的观点:

<%= react_component 'Items', { data: @items } %>

我的Items组件进行ajax调用,设置状态并呈现Item。让key={this.props.id}离开传递到映射函数的Item实例,使得组件html呈现给页面。但是添加了密钥,我收到了一个控制台错误:Uncaught TypeError: Cannot read property 'id' of undefined

此处&#39;项目&#39;:

var Items = React.createClass({
    loadItemsFromServer: function() {
        $.ajax({
            url: this.props.url,
            dataType: 'json',
            cache: false,
            success: function(data) {
                this.setState({data: data});
            }.bind(this),
            error: function(xhr, status, err) {
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    },
    componentDidMount: function() {
        this.loadItemsFromServer();
    },
    render: function() {
        var itemNodes = this.props.data.map(function() {
            return (
                <Item key={this.props.id} />
            );
        });
        return (
            <div className="ui four column doubling stackable grid">
                {itemNodes}
            </div>
        );
    }
});

我的item.js.jsx组件只格式化每个Item

var Item = React.createClass({
    render: function() {
        return (
            <div className="item-card">
                <div className="image">

                </div>
                <div className="description">
                    <div className="artist">{this.props.artist}</div>
                </div>
            </div>
        );
    }
});

React dev工具扩展显示了Items中的props和state数据。然而,孩子们都是空的。

enter image description here

我了解this,但我设置了this.props.id的密钥。我不确定我错过了什么?

2 个答案:

答案 0 :(得分:1)

我在Items组件

中发现了您发布的代码的几个问题
  1. 您正在呈现this.props.data,而实际上this.state.data是使用ajax请求更新的this.state.data。您需要呈现props,但需要从var Item = React.createClass({ render: function() { return ( <div className="item-card"> <div className="image"> </div> <div className="description"> <div className="artist">{this.props.artist}</div> </div> </div> ); } }); var Items = React.createClass({ getInitialState: function() { return { // for initial state use the array passed as props, // or empty array if not passed data: this.props.data || [] }; }, loadItemsFromServer: function() { var data = [{ id: 1, artist: 'abc' }, { id: 2, artist: 'def' }] this.setState({ data: data }); }, componentDidMount: function() { this.loadItemsFromServer(); }, render: function() { // use this.state.data not this.props.data, // since you are updating the state with the result of the ajax request, // you're not updating the props var itemNodes = this.state.data.map(function(item) { // the map iterator function takes an item as a parameter, // which is the current element of the array (this.state.data), // use (item) to access properties, not (this) return ( // use key as item id, and pass all the item properties // to the Item component with ES6 object spread syntax <Item key={item.id} {...item} /> ); }); return ( <div className="ui four column doubling stackable grid"> {itemNodes} </div> ); } });
  2. 获取初始值
  3. map迭代器函数接受一个表示当前数组元素的参数,用它来访问属性而不是使用未定义的属性
  4. 更新的代码应如下所示

    <form action="/picUploader.jsp" method="POST" ENCTYPE="multipart/form-data">
    <input type="hidden" name="INDIVIDUALID" value="001">
    <input type="hidden" name="SYSTEMID" value="J">
    <select name="PICTYPEID" size="1">
    <option value="-" ></option>
    <option value="1" >FRONT</option>
    </select>
    <input type="file" name="PICTURE">
    </form>
    

    这是一个有效的例子http://codepen.io/Gaafar/pen/EyyGPR?editors=0010

答案 1 :(得分:0)

您的实施存在一些问题。

首先,您需要决定:是否要将@items从视图中传递给Items组件?或者你想异步加载它们? 因为现在我得到你想要做的两个印象......

渲染从视图传递的项目

如果要将视图中的项目传递给组件,请确保它是正确的json。您可能需要在其上调用'as_json'。

<%= react_component 'Items', { data: @items.as_json } %>

然后,在您的Component中,映射项目以呈现<Item />组件。关于你的密钥,这是第二个问题。您需要将item变量定义为map函数的回调函数,并从中读取id:

var itemNodes = this.props.data.map(function(item) {
  return (
    <Item key={item.id} artist={item.artist} />
  );
});

注意,我还将作者添加为道具,因为您在<Item />组件中使用它。

您可以删除componentDidMountloadItemsFromServer个功能,因为您没有使用它们。

异步加载项

如果您要异步加载项目,就像您在loadItemsFromServer函数中尝试的那样,首先,从您的视图中传递网址并删除{data:@items}部分,因为您将从您的组件加载项目,如:

<%= react_component 'Items', { url: items_path(format: :json) } %>

如果要渲染异步提取的项目,请使用:

var itemNodes = this.state.data.map(function(item) {
  return (
    <Item key={item.id} artist={item.artist} />
  );loadItemsFromServer
});

注意我已将this.props.map更改为this.state.map

您现在可以使用componentDidMount和loadItemsFromServer函数加载数据并将其保存到状态。