1
votes

I'm trying to have a blog feed that when a user clicks on any blog post, the route changes to display only the individual post + header. This uses some nested routes with react-router and all tutorials show how to display dynamic data further down the nest, not how to override the parent route.

Blog component:

class Blog extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const posts = [
       { id: 1, title: "Post 1", slug: "post-1" },
       { id: 2, title: "Post 2", slug: "post-2" },
       { id: 3, title: "Post 3", slug: "post-3" }
    ];
    return (
      <>
        <Header />
        <Route
          exact
          path="/"
          render={() => (
            <>
              <SidebarLeft />
              <Feed />
              <SidebarRight />
            </>
          )}
        />
        {/* I need to somehow pass the postTitle & postSlug props by only having access to the slug url param */}
        <Route path="/articles/:postSlug" component={Post} />
      </>
    );
  }
}

Feed component:

class Feed extends React.Component {
  constructor(props) {
    super(props);
  }
  render() { 
    // gets posts from props
    var jsonPosts = this.props.posts;
    var arr = [];
    Object.keys(jsonPosts).forEach(function(key) {
      arr.push(jsonPosts[key]);
    });
    return (
      <>
        {arr.map(post => (
          <Post
            key={post.id}
            postSlug={post.slug}
            postTitle={post.title}
          />
        ))}
      </>
    );
  }
}

Post component:

class Post extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <h1>{this.props.postTitle}</h1>
      <Link to={'/articles/' + this.props.postSlug}>{this.props.postSlug}</Link>
    );
  }
}

index.jsx

// renders all of react
ReactDOM.render(
  <Router>
    <Route path="/" component={Blog} />
  </Router>,
  document.getElementById('root')
);

CodeSandbox

The problem I have is the Feed works just fine, and all the Post links work. It's as soon as I click any of the posts, react doesn't know which Post I'm trying to access.

This is where I'm not sure how to proceed since all tutorials I've found simply show the Post component nested further down. How do I tell react which post I'm trying to view and have it render the appropriate route in the Blog component?

1
You have no Router component in the code in your question. Do you have one outside of Blog?Tholle
@Tholle yes I do. Edited question to include it, although I don't think it is the source of the problem.Darius Cosden
What happens if you click on the the Link components in one of the Post components? Nothing?Tholle
@Tholle It goes to "/articles/:postSlug" but displays a blank page because the route in Blog doesn't know which postSlug prop to pass. I know I could pass it through {match.params.postSlug} but I actually need to pass more info about the post that I don't want in the URL. I'll edit the question again to include this bit because I realized its importance.Darius Cosden
@Tholle That's it! Solved it, thank you! I've edited my question to include the CodeSandbox code. If you put yours as an answer, I'll gladly accept it :DDarius Cosden

1 Answers

0
votes

Your code is working fine, but you have to add some additional logic to pass down the right props when /articles/:postSlug match.

Example

class Blog extends React.Component {
  render() {
    const posts = [
      { id: 1, title: "Post 1", slug: "post-1" },
      { id: 2, title: "Post 2", slug: "post-2" },
      { id: 3, title: "Post 3", slug: "post-3" }
    ];

    return (
      <>
        <Header />
        <Switch>
          <Route
            exact
            path="/"
            render={() => (
              <Feed posts={posts} />
            )}
          />
          <Route
            path="/articles/:postSlug"
            render={props => {
              const post = posts.find(p => p.slug === props.match.params.postSlug);

              if (!post) {
                return null;
              }
              return <Post {...props} postTitle={post.title} postSlug={post.slug} />;
            }}
          />
        </Switch>
      </>
    );
  }
}