首页 文章

将AJAX结果作为道具传递给子组件

提问于
浏览
10

我正在尝试在React中创建一个博客 . 在我的主ReactBlog组件中,我正在对节点服务器进行AJAX调用以返回一组帖子 . 我想将此帖子数据作为道具传递给不同的组件 .

特别是,我有一个名为PostViewer的组件,它将显示帖子信息 . 我希望它默认显示从其父级通过props传入的帖子,否则显示通过状态调用设置的数据 .

目前,我的代码的相关部分看起来像这样 .

var ReactBlog = React.createClass({
  getInitialState: function() {
    return {
      posts: []
    };
  },
  componentDidMount: function() {
    $.get(this.props.url, function(data) {
      if (this.isMounted()) {
        this.setState({
          posts: data
        });
      }
    }.bind(this));
  },
  render: function() {
    var latestPost = this.state.posts[0];
    return (
      <div className="layout">
        <div className="layout layout-sidebar">
          <PostList posts={this.state.posts}/>
        </div>
        <div className="layout layout-content">
          <PostViewer post={latestPost}/>
        </div>
      </div>
    )
  }
});

和子组件:

var PostViewer = React.createClass({
  getInitialState: function() {
    return {
      post: this.props.post
    }
  },
  render: function() {
    /* handle check for initial load which doesn't include prop data yet */
    if (this.state.post) {
      return (
        <div>
          {this.state.post.title}
        </div>
      )
    }
    return (
      <div/>
    )
  }
});

如果我将我孩子的渲染中的if语句和内容换成this.props,上面的工作就可以了 . *但是,这意味着我以后无法通过状态更改内容,对吗?

TLDR:我想设置一个默认帖子,通过子组件中的props(AJAX调用的结果)进行查看,我希望能够通过添加onClick事件(另一个组件)来更改正在查看的帖子更新状态 .

这是正确的方法吗?

我的应用程序组件的当前层次结构是:

React Blog
 - Post List
  - Post Snippet (click will callback on React Blog and update Post Viewer)
 - Post Viewer (default post passed in via props)

谢谢!

EDIT:

所以我最终做的是使用基于this.state的值在ReactBlog中附加道具 . 这确保了当我更改状态并在子组件中正确呈现时它会更新 . 但是,要做到这一点,我必须通过所有各种子组件链接onClick回调 . 它是否正确?看起来它可能变得非常混乱 . 这是我的完整示例代码:

var ReactBlog = React.createClass({
  getInitialState: function() {
    return {
      posts: [],
    };
  },
  componentDidMount: function() {
    $.get(this.props.url, function(data) {
      if (this.isMounted()) {
        this.setState({
          posts: data,
          post: data[0]
        });
      }
    }.bind(this));
  },
  focusPost: function(slug) {
    $.get('/api/posts/' + slug, function(data) {
      this.setState({
        post: data
      })
    }.bind(this));
  },
  render: function() {
    return (
      <div className="layout">
        <div className="layout layout-sidebar">
          <PostList handleTitleClick={this.focusPost} posts={this.state.posts}/>
        </div>
        <div className="layout layout-content">
          <PostViewer post={this.state.post}/>
        </div>
      </div>
    )
  }
});

var PostList = React.createClass({
  handleTitleClick: function(slug) {
    this.props.handleTitleClick(slug);
  },
  render: function() {
    var posts = this.props.posts;

    var postSnippets = posts.map(function(post, i) {
      return <PostSnippet data={post} key={i} handleTitleClick={this.handleTitleClick}/>;
    }, this);

    return (
      <div className="posts-list">
        <ul>
          {postSnippets}
        </ul>
      </div>
    )
  }
});

var PostSnippet = React.createClass({
  handleTitleClick: function(slug) {
    this.props.handleTitleClick(slug);
  },
  render: function() {
    var post = this.props.data;
    return (
      <li>
        <h1 onClick={this.handleTitleClick.bind(this, post.slug)}>{post.title}</h1>
      </li>
    )
  }
});

var PostViewer = React.createClass({
  getInitialState: function() {
    return {
      post: this.props.post
    }
  },
  render: function() {
    /* handle check for initial load which doesn't include prop data yet */
    if (this.props.post) {
      return (
        <div>
          {this.props.post.title}
        </div>
      )
    }
    return (
      <div/>
    )
  }
});

仍然希望得到一些反馈/希望这有帮助!

3 回答

  • 0

    这是一个老问题,但我相信仍然相关,所以我要投入2美分 .

    理想情况下,您希望将任何ajax调用分离为动作文件,而不是在组件内部执行 . 没有使用像Redux这样的东西来帮助你管理你的状态(在这个时候,我会推荐redux react-redux),你可以使用一个叫做“容器组件”的东西来为你做所有重型状态的提升然后在正在进行主布局的组件中使用props . 这是一个例子:

    // childComponent.js
    import React from 'react';
    import axios from 'axios'; // ajax stuff similar to jquery but with promises
    
    const ChildComponent = React.createClass({
      render: function() {
        <ul className="posts">
          {this.props.posts.map(function(post){
            return (
              <li>
                <h3>{post.title}</h3>
                <p>{post.content}</p>
              </li>
            )
          })}
        </ul>
      }
    })
    
    const ChildComponentContainer = React.createClass({
      getInitialState: function() {
        return {
          posts: []
        }
      },
      componentWillMount: function() {
        axios.get(this.props.url, function(resp) {
          this.setState({
            posts: resp.data
          });
        }.bind(this));
      },
      render: function() {
        return (
          <ChildComponent posts={this.state.posts} />
        )
      }
    })
    
    export default ChildComponentContainer;
    
  • 0

    博客在很大程度上是静态的,因此您可以利用React不可变结构始终“渲染所有内容”而不是使用状态 .

    一种选择是使用路由器(如page.js)来获取数据 .

    这是一些代码http://jsbin.com/qesimopugo/1/edit?html,js,output

    如果您不明白,请告诉我;)

  • 2

    摆脱isMounted并使用context如果你将回调传递到几个级别

相关问题