Something wrong with my way to fetch data?

2019-07-29 15:32发布

问题:

I am trying to build CRUD app with react and redux in client side, and I am stuck in this problem for weeks.

I have 2 main components: one for a list of articles and other for an article.
I am calling AJAX get request with componentDidMount to the server that retrieves the data:

class Category1 extends React.Component {
    componentDidMount(){
       this.props.fetchArticles();
    }
    render() {
        return (
           <div>
             {this.props.children ||
               <div className="mainContent">
                    <h1>Category1</h1> <hr />
                    <ListContainer articles={this.props.articles}/>
               </div>
             }
           </div>
         );
      }
}   

and in the ListContainer, I am iterating data over a list and rendering them with <Link> like this:

export default class ListContainer extends React.Component {
   renderItem(article){
      return (
         <Link to={"/articles/" + article.id} key={article.id} >
             <ItemContainer article={article} />
         </Link>
      )
   }
   render(){
       <div className="row">
           <div  className="col-lg-8 col-md-8 col-sm8">
              {this.props.articles.map(this.renderItem.bind(this))}
           </div>
        </div>
   }
}

When I click an article in a list, it will take me to an article page which also uses componentDidMount to retrieve data of its article.
An article page component:

class ArticlePage extends React.Component {
    componentDidMount(){
        this.props.fetchArticle(this.props.params.id);
    }
    render() {
       return (
          <div className="row">
              <div className="col-lg-6 col-md-6 col-sm6">
                 <div className="article-content">
                    <h2>{this.props.article.title}</h2>
                    <div className="article-body">
                       <p>{this.props.article.image}</p>
                       <p>by {this.props.article.name}</p>
                    </div>
                 </div>
               </div>
          </div>
       );
    }
 }

My problem is once I access to ArticlePage, I cannot go back to a previous page or go to the other pages from it. It stays in the same page even though a path will change, and I get a console error saying "this.props.articles.map is not a function" which ArticlePage does not have. I am sure its error comes from ListContainer. Also, when I reload the ArticlePage, its components just disappears without getting any error.

This is my routes:

<Route path="/" component={App}>
  <IndexRoute component={Home}/>
  <Route path="login" component={LoginPage}/>
  <Route path="signup" component={SignupPage}/>
  <Route path="submit" component={auth(SubmitPage)}/>
  <Route path="category1" component={Category1}>
     <Route path="articles/:id" component={ArticlePage} />
  </Route> 
  <Route path="category2" component={Category2}>
     <Route path="articles/:id" component={ArticlePage} />
  </Route>  
</Route>

How can I fix this?

回答1:

Not sure how you have your routes setup, but this should get you started using react-router.

Firstly you should set up your routes where you set up your application.

Your index.js or root page.

import { Router, Route, Link, browserHistory } from 'react-router'
/* imports */

render((
  <Router history={browserHistory}>
    <Route path="/articles" component={Politics}>
      <Route path="/article/:id" component={ArticlePage}/>
    </Route>
  </Router>
), document.getElementById('root'))

Then in your ListContainer Component create your links to articles.

Your list-container.js

export default class ListContainer extends React.Component {
  renderItem(article){
    return (
      <Link to={"/articles/" + article.id}>
        <ItemContainer article={article} /> // <- ??
        // Not sure about this part as you do not
        // have ItemContainer specified in your question.
        // Assumption that you are rendering ArticlePage
        // when this link is followed.
      </Link>
    )
  }
  render(){
    <div className="row">
      <div className="col-lg-8 col-md-8 col-sm8">
        {this.props.articles.map(this.renderItem.bind(this))} 
      </div>
    </div>
  }
}

Finally in your ArticlePage Component, create a link back to your parent component.

Your article-page.js

class ArticlePage extends React.Component {
  componentDidMount(){
    this.props.fetchArticle(this.props.params.id);
  }
  render() {
    return (
      <div className="row">
        <div className="col-lg-6 col-md-6 col-sm6">
          <Link to={"/articles"}>Articles</Link>
          <div className="article-content">
            <h2>{this.props.article.title}</h2>
            <div className="article-body">
              <p>{this.props.article.image}</p>
              <p>by {this.props.article.name}</p>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

You can find the docs on react-router here.