admin管理员组

文章数量:1327660

I'm a newbie in React js and currently i'm building a layout that contains from many ponents

For example, a home page layout that contains sidebar ponent, topbar ponent, footer ponent and main content ponent.

When i click on a link in sidebar ponent, the main content will be changed based on url of link i clicked on and other ponents will be same on all pages regardless of url.

Here is my code:

MainLayout.js

import React, { Component } from 'react';  
import { Route } from 'react-router-dom';  

import Sidebar from '../ponents/Sidebar';
  
const MainLayout = ({children, ...rest}) => {  
  return (  
    <div className="page page-dashboard">  
      {/* <div className="sidebar"><Sidebar></Sidebar></div>   */}
      <div className="main">
        {children}
      </div>  
    </div>  
  )  
}  
  
const MainLayoutRoute = ({ponent: Component, ...rest}) => {  
  return (  
    <Route {...rest} render={matchProps => (  
      <MainLayout>  
          <Component {...matchProps} />  
      </MainLayout>  
    )} />  
  )  
};  
  
export default MainLayoutRoute; 

MainPage.js

import React, { Component }  from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';  

import  Sidebar from './Sidebar';
import  Header from './Header';
import  Footer from './Footer';

import UsersList from './UsersList';

export default class MainPage extends Component {
    render() {
        return (
            <Router>
            <div>
              <Header/>
              <Sidebar/>
              <div className="wrapper">
                <Switch>
                  <Route path={"/users"} ponent={UsersList} />
                </Switch>
              </div>
              <Footer></Footer>
              
            </div>
          </Router>
        );
    }
}

Sidebar.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch, Link } from 'react-router-dom';  

export default class Sidebar extends Component {
    render() {
        return (
            <div className="sidenav">
            <ul>
                <li><Link to="/users">Users</Link></li>
                <li><Link to="/settings">Setting</Link></li>
            </ul>
          </div>
          
        );
    }
}

UserList.js

import React, { Component }  from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch, Link } from 'react-router-dom';  

export default class UsersList extends Component {
    render() {
        return (
            <div>
           <button><Link to="/newuser">Add new user</Link></button>
           </div>
        );
    }
}

App.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';  
import logo from './logo.svg';
import './App.css';
import './css/custom.scss';

/** Layouts **/  
import LoginLayoutRoute from "./layouts/LoginLayout";  
import MainLayoutRoute from "./layouts/MainLayout";  
  
/** Components **/  
import MainPage from './ponents/MainPage';  
import LoginPage from './ponents/LoginPage'  

export default class App extends Component {
  render() {
    return (
      <Router>  
        <Switch>  
          <Route exact path="/">  
            <Redirect to="/login" />  
          </Route>  
          <LoginLayoutRoute path="/login" ponent={LoginPage} />  
          <MainLayoutRoute path="/home" ponent={MainPage} />
        </Switch>  
      </Router>  
    );
  }
 
}

But when i refresh the page, it turned blank like this:

Before i refresh page

After i refresh page

How can i fix this ?

I'm a newbie in React js and currently i'm building a layout that contains from many ponents

For example, a home page layout that contains sidebar ponent, topbar ponent, footer ponent and main content ponent.

When i click on a link in sidebar ponent, the main content will be changed based on url of link i clicked on and other ponents will be same on all pages regardless of url.

Here is my code:

MainLayout.js

import React, { Component } from 'react';  
import { Route } from 'react-router-dom';  

import Sidebar from '../ponents/Sidebar';
  
const MainLayout = ({children, ...rest}) => {  
  return (  
    <div className="page page-dashboard">  
      {/* <div className="sidebar"><Sidebar></Sidebar></div>   */}
      <div className="main">
        {children}
      </div>  
    </div>  
  )  
}  
  
const MainLayoutRoute = ({ponent: Component, ...rest}) => {  
  return (  
    <Route {...rest} render={matchProps => (  
      <MainLayout>  
          <Component {...matchProps} />  
      </MainLayout>  
    )} />  
  )  
};  
  
export default MainLayoutRoute; 

MainPage.js

import React, { Component }  from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';  

import  Sidebar from './Sidebar';
import  Header from './Header';
import  Footer from './Footer';

import UsersList from './UsersList';

export default class MainPage extends Component {
    render() {
        return (
            <Router>
            <div>
              <Header/>
              <Sidebar/>
              <div className="wrapper">
                <Switch>
                  <Route path={"/users"} ponent={UsersList} />
                </Switch>
              </div>
              <Footer></Footer>
              
            </div>
          </Router>
        );
    }
}

Sidebar.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch, Link } from 'react-router-dom';  

export default class Sidebar extends Component {
    render() {
        return (
            <div className="sidenav">
            <ul>
                <li><Link to="/users">Users</Link></li>
                <li><Link to="/settings">Setting</Link></li>
            </ul>
          </div>
          
        );
    }
}

UserList.js

import React, { Component }  from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch, Link } from 'react-router-dom';  

export default class UsersList extends Component {
    render() {
        return (
            <div>
           <button><Link to="/newuser">Add new user</Link></button>
           </div>
        );
    }
}

App.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';  
import logo from './logo.svg';
import './App.css';
import './css/custom.scss';

/** Layouts **/  
import LoginLayoutRoute from "./layouts/LoginLayout";  
import MainLayoutRoute from "./layouts/MainLayout";  
  
/** Components **/  
import MainPage from './ponents/MainPage';  
import LoginPage from './ponents/LoginPage'  

export default class App extends Component {
  render() {
    return (
      <Router>  
        <Switch>  
          <Route exact path="/">  
            <Redirect to="/login" />  
          </Route>  
          <LoginLayoutRoute path="/login" ponent={LoginPage} />  
          <MainLayoutRoute path="/home" ponent={MainPage} />
        </Switch>  
      </Router>  
    );
  }
 
}

But when i refresh the page, it turned blank like this:

Before i refresh page

After i refresh page

How can i fix this ?

Share Improve this question edited Jun 30, 2020 at 9:17 Binh Nguyen Xuan asked Jun 30, 2020 at 3:56 Binh Nguyen XuanBinh Nguyen Xuan 311 gold badge1 silver badge3 bronze badges 7
  • other ponents will be same on all pages regardless of url => could u please explain this line? – solanki... Commented Jun 30, 2020 at 4:00
  • ah ok, i will explain through example. For example: the side bar have a item call user with the url is "/user". When i click on that item, it will be navigated to user page. In the user page, the default ponent such as sidebar, topbar, footer will be same as main layout. That's what i mean – Binh Nguyen Xuan Commented Jun 30, 2020 at 4:04
  • Wele to StackOverflow. Please review How do I ask a good question to see what you need to give us, and update your question with details of the specific problem and what you have tried to solve it, and include your relevant code in a minimal,reproducible example, so we are able to help. – FluffyKitten Commented Jun 30, 2020 at 4:06
  • My app has two layout, the login layout and the main layout. In the main layout, there are some of default ponents such as sidebar, topbar, footer, main content. When i click on one item in the sidebar, the main content will render ponent based on the item that i clicked on and also the url like the example i explain above – Binh Nguyen Xuan Commented Jun 30, 2020 at 4:11
  • Hope this helps : tszekely.github.io/react-learning-module/step-02 – solanki... Commented Jun 30, 2020 at 4:39
 |  Show 2 more ments

1 Answer 1

Reset to default 5

The more direct answer to your question, is position. If you are into reading, here is a good overview: Composition

To elaborate further with an example, since no code was provided, I will create some fictitious functional ponents to demonstrate the process. I also introduced a library that will be used to conduct the routing on the front end called "React Router". For your reference here is a link: React Router

Layout ponent:

import React from "react";
import {Link} from "react-router-dom";

const Layout = (props) => {
return <div>
   <ul>
       <li><Link to={"/home"}>Home</Link></li>
       <li><Link to={"/setting"}>Setting</Link></li>
       <li><Link to={"/payment"}>Payment</Link></li>
  </ul>
  {props.children}
</div>
};
export default Layout;

The Layout ponent will contain the elements shared across the other ponents. The links, side bar, etc...

The key item from the Layout ponent is the "props.children". Remember React will do a differential parison between the virtual dom and the "real" dom to know what parts to replace. So when a link is clicked the "React Router Library" will update the "url" more specifically the path "/home" to "/setting" for example, which will in turn load the ponent into the content section "props.children".

Finally, in order to connect all the pieces:

import React from "react";
import Layout from "./Layout";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import Home from "./Home";
import Setting from "./Setting";
import Payment from "./Payment";

const App = () => {
return <Router>
   <Layout>
       <Switch>
          <Redirect exact={true} from={"/"} to={"/home"}/>
          <Route path={"/home"}><Home/></Route>
          <Route path={"/setting"}><Setting/></Route>
          <Route path={"/payment"}><Payment/></Route>
       </Switch>
   </Layout>
 </Router>
};
export default App;

I skipped over the creation of the home/setting/payment ponents, as they are not critical to the explanation.

The key take from the App ponent is notice where the "Layout" ponent is placed "It is wrapping the other ponents". Remember in the previous section I mentioned that when you click on a link the ponent will be placed in the content section. Here we defined the routes for each ponent. The path "/home" equates to the "Home" ponent, and when the link in the "side bar" for example is clicked, the ponent "Home" will be loaded, and placed within the "Layout" ponent, but the Layout elements remain.

Hope this answers your question. Good luck.


Additional clarification to address code added.

Your App.js file after the modification:

import React, { Component } from 'react';
import { Router, Route, Redirect, Switch } from 'react-router-dom';  
import logo from './logo.svg';
import './App.css';
import './css/custom.scss';

/** Layouts **/  
import LoginLayout from "./layouts/LoginLayout";  
import MainLayout from "./layouts/MainLayout";  
  
/** Components **/  
import MainPage from './ponents/MainPage';  
import LoginPage from './ponents/LoginPage'  

const App = () => {
  return (
      <Router history={history}>  
        <Switch>  
          <Redirect exact={true} from="/" to="/login" />
<Route path="/login" render={() => <LoginLayout><LoginPage/></LoginLayout>}/>
          <MainLayout>
            <Route path="/home" ponent={MainPage} />
            <Route path={"/users"} ponent={UsersList} />
          </MainLayout
        </Switch>  
      </Router>  
    );
};

export default App;

Your layouts do not need to have routes in them. Just add your routes to the App.js file and wrap the generated route ponent with the desired layout.

I added the "/users" route in here as well. That should fix your refresh problem.

MainLayout.js

import React, { Component } from 'react';  
import { Route } from 'react-router-dom';  

import Sidebar from '../ponents/Sidebar';
  
const MainLayout = ({children}) => {  
  return (  
    <div className="page page-dashboard">  
      {/* <div className="sidebar"><Sidebar></Sidebar></div>   */}
      <div className="main">
        {children}
      </div>  
    </div>  
  )  
}  
  
export default MainLayoutRoute; 

Abstracted the route from the layout ponent, it does not need to know about it.

MainPage.js

import React, { Component }  from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';  

import  Sidebar from './Sidebar';
import  Header from './Header';
import  Footer from './Footer';

import UsersList from './UsersList';

export default class MainPage extends Component {
    render() {
        return (
            <Router>
            <div>
              <Header/>
              <Sidebar/>
              <div className="wrapper">
                <Switch>
                  <Route path={"/users"} ponent={UsersList} />
                </Switch>
              </div>
              <Footer></Footer>
              
            </div>
          </Router>
        );
    }
}

Seems here you are trying to do multiple things. This to me looks like a Layout ponent, so perhaps you can remove the code from here and put it into the MainLayout ponent. Then identify what should go into the MainPage. Just like you are trying to do with the UsersList, it renders content, perhaps the MainPage can display different data?

In the Sidbar.js file:

<li><Link to="/settings">Setting</Link></li>

This wont work until you create an associated Route in the App.js file, and a Component to render.

In the UserList.js you have the following code:

<button><Link to="/newuser">Add new user</Link></button>

But you do not have have newuser ponent. So when you do create a NewUser ponent, you will also need to add a "Route" as a child to the MainLayout ponent in the App.js file.

If you notice in the App.js file I imported and created the following for you:

import {createBrowserHistory} from "history";
export const history = createBrowserHistory();

And passed it as a prop to the Router:

<Router history={history}>

In your LoginPage, if you need to redirect after a successful login, you can do the following:

import {history} from "../App";

Import history from the App Component.

Then in the button's onClick method push "/main" to the stack.

<button onClick={() => history.push("/main")}>Login</button>

本文标签: