2015-02-18 20 views
10

Próbuję utworzyć bloga w React. W moim głównym komponencie ReactBlog wykonuję wywołanie AJAX do serwera węzła, aby zwrócić tablicę wpisów. Chcę przekazać dane tego posta do różnych komponentów jako rekwizytów.Przekazywanie wyników AJAX jako rekwizytów do komponentu potomnego

W szczególności mam komponent o nazwie PostViewer, który będzie wyświetlał informacje o postach. Chcę, aby domyślnie pokazywał przekazywany post od swojego rodzica za pomocą rekwizytów, i w przeciwnym razie pokazywał dane ustawiane przez wywołanie stanu.

Obecnie odpowiednie części mojego kodu wyglądają tak.

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

i składnik dziecko:

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

Powyższe prace czy mogę zamienić się z treścią oświadczenia i jeśli w moim dziecka oddać this.props * Jednak to oznaczałoby, że nie mogłem”. t zmienić zawartość później przez stan, prawda?

TLDR: Chcę ustawić domyślny wpis, który będzie wyświetlany przez rekwizyty w komponencie potomnym (wyniki wywołania AJAX), i chcę mieć możliwość zmiany, który post jest oglądany, dodając zdarzenia onClick (innego składnik), który zaktualizuje stan.

Czy to jest właściwy sposób, aby o tym poradzić?

Obecna hierarchia elementów mojej aplikacji są:

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

Dzięki!

EDIT:

Więc co skończyło się robi został mocowania podpory w ReactBlog używając wartości w oparciu o this.state. Zapewniło to, że będzie aktualizowany po zmianie stanu i renderowaniu w składnikach potomnych. Jednakże, aby to zrobić, musiałem połączyć łańcuchowe wywołania zwrotne przez wszystkie różne składniki podrzędne. Czy to jest poprawne? Wygląda na to, że może być BARDZO brudny. Oto mój pełny przykładowy kod:

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

Nadal mam nadzieję uzyskać pewne informacje zwrotne/mam nadzieję, że to pomoże!

+0

Robisz to wszystko po edycji. Używanie stanu w komponencie macierzystym, aby zapewnić dzieciom rekwizyty, jest drogą do zrobienia. Twój problem polegał na tym, że "getInitialState" wykonuje się tylko raz dla każdego komponentu (chyba że zostanie odmontowany), więc gdy zmienisz stan macierzysty, nawet wtedy, gdy rekwizyty dziecięce również się zmienią, jego stan nie będzie. – GonArrivi

Odpowiedz

0

Blog jest w większości statyczny, więc można wykorzystać React niezmienne struktury, aby "renderować wszystko" przez cały czas, zamiast używać stanu.

Jedną z opcji jest użycie routera (takiego jak page.js) do pobrania danych.

Oto kod http://jsbin.com/qesimopugo/1/edit?html,js,output

Jeśli czegoś nie rozumiesz po prostu daj mi znać;)

0

członkowskie powinno być głównym reagują widoku plików, nie dla komponentów wielokrotnego użytku, jak tutaj PostViewer, to będzie po prostu renderuj tytuł postu, jeśli ma on tytuł jako rekwizyty, w przeciwnym razie będzie renderowany jako pusty.

var PostViewer = React.createClass({ 

    render: function() { 

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

To stara sprawa, ale wierzę, że nadal aktualne, więc mam zamiar rzucić w moim 2 centy.

Idealnie chcesz oddzielić wszystkie wywołania ajaxowe na pliki akcji, zamiast wykonywać je bezpośrednio wewnątrz komponentu. Bez wchodzenia w użycie czegoś takiego jak Redux, aby pomóc ci w zarządzaniu swoim stanem (który w tym momencie chciałbym polecić redux + react-redux), możesz użyć czegoś zwanego "komponentami kontenera", aby wykonać wszystkie ciężkie podnoszenie stanu dla ty, a następnie użyj rekwizytów w komponencie, który wykonuje główny układ. Oto przykład:

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

to zdecydowanie świetny sposób na zrobienie tego :) – Jon

Powiązane problemy