1

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?

kay
  • 1,369
  • 4
  • 15
  • 27

1 Answers1

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.

alex
  • 5,467
  • 4
  • 33
  • 43
  • I do not think it is because of react-router or how I set it up my routes. As I said, I can access to the ArticlePage component, but I cannot go to other pages from ArticlePage or reload the page. – kay Sep 06 '16 at 11:12
  • Did you try the suggestion to add a link inside article page? Also when you say 'reload' what do you mean? – alex Sep 06 '16 at 11:19
  • No I didn't. I will try. I meant refresh a page. I just tried it, but it did not work. Also when I remove componentDidMount method from ArticlePage, it will work but not fetching data. – kay Sep 06 '16 at 11:24
  • Okay, so react-router doesn't 'reload' your page the same way your browser would normally handle a page route or refresh, it actually manipulates your DOM according to the components. From the docs, "React Router keeps your UI in sync with the URL." So essentially you are trying to do two different things. React is designed for 'single-page' applications, and it handles the view without refreshing the entire page, but simply updating the difference using a virtual DOM. Much more complicated than that, but with limited space... – alex Sep 06 '16 at 11:30
  • http://stackoverflow.com/questions/21109361/why-is-reacts-concept-of-virtual-dom-said-to-be-more-performant-than-dirty-mode – alex Sep 06 '16 at 11:31
  • So I want to cleanup my previous state? How should I change my code? – kay Sep 06 '16 at 11:51
  • Any component that isn't nested inside another directly should be in your routes. Hard to tell with your naming convention as well, rationalise that a little better to make it obvious what is going on. For example is Politics == Category1 ? Links are to separate components and not nested components. That sort of thing. Without seeing your entire code base and spending some time working through it all, it is hard to be more specific. Hopefully your on the right track now. – alex Sep 06 '16 at 11:57
  • I did not mean to write Politics, and I changed it. I think you are right. I will try to fix it later, and if I will be able to fix it, I will accept this as the answer. Thank you! – kay Sep 06 '16 at 12:07
  • My pleasure, happy to help. Any problems post another question and I or someone here will pick it up and help out. – alex Sep 06 '16 at 12:09