2015-02-18 4 views
10

Я пытаюсь создать блог в React. В моем основном компоненте ReactBlog я делаю вызов AJAX на сервер узлов, чтобы возвращать массив сообщений. Я хочу передать эти данные сообщения различным компонентам в качестве реквизита.Передача результатов AJAX в качестве реквизита для дочернего компонента

В частности, у меня есть компонент, называемый PostViewer, который будет отображать информацию о сообщении. Я хочу, чтобы он по умолчанию показывал сообщение, переданное от родителя через реквизит, и в противном случае показывал данные, которые устанавливаются с помощью государственного вызова.

В настоящее время соответствующие части моего кода выглядят так.

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/> 
    ) 
    } 
}); 

Вышеуказанных работы, если я поменять, если заявление и содержание в моем ребенке вынести на this.props * Тем не менее, это будет означать, что я не мог. t изменить содержимое позже через состояние, правильно?

TLDR: Я хочу установить пост по умолчанию для просмотра через реквизит в дочернем компоненте (результаты вызова 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:

Так что я в конечном итоге делает была прикрепление реквизита в ReactBlog, используя значение, основанное на this.state. Это гарантировало, что он обновляется, когда я меняю состояние и правильно рисую дочерние компоненты. Однако для этого мне пришлось подключать callback-запросы 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/> 
    ) 
    } 
}); 

Все еще надеемся получить некоторые отзывы/надеюсь, что это поможет!

+0

Вы делаете все сразу после издания. Использование состояния в родительском компоненте для предоставления реквизита для детей - это путь. Ваша проблема заключалась в том, что «getInitialState» выполняется только один раз для каждого компонента (если он не размонтирован), поэтому, когда вы изменили родительское состояние, даже если дочерние реквизиты тоже изменились, его состояние не будет. – GonArrivi

ответ

0

Блог по-статичен по большей части, поэтому вы можете использовать React неизменяемые структуры для «рендеринга всего» все время, а не для использования состояния.

Один из вариантов заключается в использовании маршрутизатора (например, page.js) для извлечения данных.

Вот код http://jsbin.com/qesimopugo/1/edit?html,js,output

Если вы не понимаете, что-то просто дайте мне знать;)

0

государство должно быть основным видом реагировать файл, а не для повторно используемых компонентов, как здесь PostViewer, это будет просто сделать сообщение заголовком, если оно имеет название в качестве реквизита, иначе оно будет отображаться пустым.

var PostViewer = React.createClass({ 

    render: function() { 

    if (this.props.hasOwnProperty('title')) { 
     return (
     <div> 
      {this.props.title} 
     </div> 
    ) 
    } 
    return (
     <div/> 
    ) 
    } 
}); 
0

Избавьтесь от isMounted и использовать context, если вы передаете функции обратного вызова вниз несколько уровней

2

Это старый вопрос, но я считаю, по-прежнему актуальна, так что я собираюсь бросить в мой 2 цента.

В идеале вы хотите выделить любые вызовы ajax в файл действий, а не делать это прямо внутри компонента. Не вдаваясь в что-то вроде Redux, чтобы помочь вам управлять своим состоянием (которое в данный момент я бы рекомендовал для уменьшения x + response-redux), вы могли бы использовать что-то, называемое «компонентами контейнера», чтобы выполнить весь тяжелый подъем состояния для вы, а затем используете реквизиты в компоненте, который выполняет основную компоновку. Вот пример:

// 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

это, безусловно, отличный способ сделать это :) – Jon

Смежные вопросы