首页 > 解决方案 > Nested React Router Component Won't Render on New Page

问题描述

I have a react app that consists of a main Component. , which comprises a element with navbar markup.

//app.js
    import React, { Component } from 'react';
    import {
      Route,
      NavLink,
      BrowserRouter,
      Switch,
    } from "react-router-dom";

    import Home from './components/home';
    import Create from './components/create';
    import './App.css';

    const pathBase = 'http://127.0.0.1:8000';
    const pathSearch = '/posts/';

    class App extends Component {
      constructor(props) {
        super(props);

        this.state = {
          posts: [],
          post: null,
          error: null,
        }

      }


      setPostsState = result => {
        this.setState({ posts: result})
      }

      setPostState = post => {
        this.setState({ post: post});
        console.log(this.state.post)

      }

      retrievePost = (event, post) => {
        event.preventDefault();
        this.fetchPost(post);

      }

      deletePosts = id => {
        fetch(`${pathBase}${pathSearch}${id }`, { method: 'DELETE'})
        .then(res => res.status === 204 ? this.fetchPosts() : null)
      }

      editPosts = id => {
        fetch(`${pathBase}${pathSearch}${id }`, { method: 'PUT'})
        .then(res => res.status === 204 ? this.fetchPosts() : null)
      }

      fetchPost = (post) => {
        fetch(`${pathBase}${pathSearch}${post.id}`)
          .then(response => response.json())
          .then(result => this.setPostState(result))
          .catch(error => console.log(error));
      }

      fetchPosts = () => {
        fetch(`${pathBase}${pathSearch}`)
          .then(response => response.json())
          .then(result => this.setPostsState(result))
          .catch(error => this.setState({ error: error }));
      }

      componentDidMount() {
        this.fetchPosts();
      }


      render() {
        const { posts, error } = this.state;

        if (error) {
          return <div className="container">
                  <h3>Error: {error.message}</h3>
                </div>;
        }

        return (
          <BrowserRouter>
            <div className="container">
            <header>
              <nav className="navbar navbar-expand-md navbar-light bg-light">
                <a className="navbar-brand" href="">Django Rest API</a>
                <div className="collapse navbar-collapse" id="navbarSupportedContent">
                  <ul className="navbar-nav mr-auto">
                    <li className="nav-item active">
                      <NavLink to="/posts">Posts</NavLink>
                    </li>
                    <li className="nav-item">
                      <NavLink to="/create">Create</NavLink>
                    </li>
                  </ul>
                </div>
              </nav>
            </header>
            <Switch>

            <Route path="/create" 
                   render={(props) => 
                  <Create {...props}
                    fetchPosts={this.fetchPosts} 
                  />
                } 
            />

               <Route path="/posts" 
                render={(props) => 
                  <Home {...props} 
                    posts={posts} 
                    deletePost={this.deletePosts} 
                  />
                } 
            />

            </Switch>

          </div>
          </BrowserRouter>

        );
      }
    }

    export default App;

There is also a (using React-Router v4) which path="/posts" that renders a Component . This component consists of a list which maps over blog posts obtained from the DB. Each post displays as a card with the post name serving as a link, that when the user clicks should bring up the component to show Post details.

// components/home.js
import React, { Component } from 'react';
import Post from './post';
import {
    Route,
    NavLink,    
  } from "react-router-dom";

class Home extends Component {


    render() {
        const ulStyle = { listStyleType: 'none' }
        const { deletePost, posts } = this.props;
        const match = this.props;
        console.log(match)

        return (
            <ul style={ ulStyle }>
            <h3>Posts</h3>
            {posts.map(post =>
            <li 
                key={posts.indexOf(post)}
                value={post.id} 
            >
              <div className="card">
                <div className="card-body">
                    <NavLink to={`/posts/${post.id}`}>{post.title} 
  </NavLink>, Created: {post.timestamp}
                <button type="button"
                  onClick={() => deletePost(post.id)} 
                  className="float-right btn btn-outline-danger btn-sm"
                >
                  Delete
                </button>
                </div>

                </div>
              </li>


              )}

              <Route exact path={`/posts/:postId`} render={(props) => 
 (<Post {...props} posts={posts}/>)}/>   

          </ul>
        );
    }
}

export default Home;

I am having trouble getting the post component to render on a new page. Currently if the user clicks a link, the component renders at the bottom of the existing page (the component). I need the Post component to render on a entirely new page. How did I do this?

import React, { Component } from 'react';

class Post extends Component {

    render() {  
        const { children, match, posts} = this.props;
        console.log(match);
        console.log(posts);

        const p = (posts) => {
            posts.find(post => post === match.postId)
        }

        return (
                <div>
                    {match.params.postId}
                    <p>HELLO WORLD</p>
                </div>
         );
        }
    }


export default Post;

标签: reactjsreact-router

解决方案


您所看到的是 React Router 嵌套路由的预期行为。嵌套路由的内容将作为其父组件的一部分呈现。

它是这样设计的,以便在导航时将重新渲染的次数保持在最低限度(当嵌套路由更改时,父组件的内容不会重新渲染)。

如果要更改整个页面内容,则不应使用嵌套路由。只需将您拥有的所有路由放在Switch组件下即可。换句话说,将您的单个发布路线移动到App组件。


推荐阅读