ko_ma
ko_ma

Reputation: 1021

React: first time, undefined error, but after reload, it success

I make web application with react, redux, redux-thunk, react-router-dom v4.

I have created a component that loads a post.

But at the beginning, the value is undefined, and the value is loaded successfully when I reload page.

Why will not the value come in at first?

App.js:

...
{this.props.posts.map((post, index) => (
          <div key={index} style={{ border: "1px solid black" }}>
            <Link to={`/post/${post._id}`}>{post.title}</Link>
            <br />
            <span>{post.content}</span>
            <br />
            <span>{post.author}</span>
          </div>
        ))}
...

Post.js:

class Post extends Component {
  componentDidMount() {
    this.props.getPostDetailFetch(this.props.match.params.id);
  }

  render() {
    return (
      <Container>
        <Row>
          <Col xs="12">
            <h1>{this.props.post.title}</h1>
          </Col>
          <Col xs="12">
            <h3>{this.props.post.author}</h3>
           <Col xs="12">
            <p>{this.props.post.content}</p>
           </Col>
        </Row>
      </Container>
       );
    }
  }
 ...

index.js:

import { Router, Route } from "react-router-dom";
import history from "./history";

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
     <div>
        <Route exact path="/" component={App} />
        <Route path="/post/:id" component={Post} />
     </div>
    </Router>
  </Provider>,
   document.getElementById("root")
  );

Upvotes: 0

Views: 2233

Answers (1)

devserkan
devserkan

Reputation: 17608

It does not work because you are fetching posts in an asynchronous way. So, in the first render they are undefined. Just use conditional rendering:

...
{!!this.props.posts.length && this.props.posts.map((post, index) => (
          <div key={index} style={{ border: "1px solid black" }}>
            <Link to={`/post/${post._id}`}>{post.title}</Link>
            <br />
            <span>{post.content}</span>
            <br />
            <span>{post.author}</span>
          </div>
        ))}
...

The same problem goes for Post.js. So, you should also do the conditional rendering there.

render() {
    if ( !this.props.post) {
        return <div>No post!</div>
    }

    return (
      <Container>
        <Row>
          <Col xs="12">
            <h1>{this.props.post.title}</h1>
          </Col>
          <Col xs="12">
            <h3>{this.props.post.author}</h3>
           <Col xs="12">
            <p>{this.props.post.content}</p>
           </Col>
        </Row>
      </Container>
       );
    }

Also, if the post detail is not different then in the posts array, I think you don't need to do a fetch again here. Just change your logic and with id get the post detail from store somehow.

Upvotes: 3

Related Questions