路由模块,需要一个路由容器,标识着使用了那种模式的路由
import {容器} from "react-router-dom";
// 容器中存放的就是路由:HashRouter 或者 BrowserRouter
// 这2种都可以,并且都是组件,为了我们方便来回使用方便一般都会给他们起个别名
//⚠️ 起完别名之后,则BrowserRouter这个名字就作废了。
import {BrowserRouter as Router} from "react-router-dom";
在以下案例中均已,Router 为BrowserRouter。
Route
import {BrowserRouter as Router,Route} from "react-router-dom";
⚠️ Router 路由盒子,只能有一个根节点
修改前
import React,{Component} from "react";
import ReactDOM from "react-dom";
import {BrowserRouter as Router,Route} from "react-router-dom";
render(
//直接Router 放在第一个根节点会报错,Error: Router只能有一个child
//所以要加一个 <>>或者 div 包起来
,wondow.root)
修改后
import React,{Component} from "react";
import ReactDOM from "react-dom";
import {BrowserRouter as Router,Route} from "react-router-dom";
render(
<>
>
,wondow.root)
每条路由都和对应的组件创建链接
默认路由都是从上到下匹配,如果匹配成功就会渲染对应的组件
import React,{Component} from "react";
import ReactDOM from "react-dom";
import {BrowserRouter as Router,Route} from "react-router-dom";
import Home from "./pages/Home";
import Proile from "./pages/Proile";
render(
<>
>
,wondow.root)
路由匹配的问题
render(
<>
>
,wondow.root)
解决404问题,在后端处理,找不到的话就返回首页,首页会根据当前的路径再次渲染路由。
import {BrowserRouter as Router,Route,Redirect} from "react-router-dom";
render(
<>
>
,wondow.root)
import {BrowserRouter as Router,Route,Redirect} from "react-router-dom";
render(
,wondow.root)
路由导航
import {BrowserRouter as Router,Route,Redirect,NavLink} from "react-router-dom";
render(
<>
//
>
,wondow.root)
布局:nav.js 存放导航,index.js 存放路由并渲染到页面,home.js /user.js 是导航对应的内容
需求:每个页面都各自存放自己的东西,采用另一个app.js 页面把路由和导航组合到一起,这样就不需要把导航文件引入到index.js路由页面了
index.js
import App from "./app";
render(
,wondow.root)
App.js
import React,{Component} from "react";
import ReactDOM from "react-dom";
import Nav from "./nav";
export default class App extends Component{
constructor(){
super();
}
render(
return(
{this.props.children}
)
)
}
改写user.js
import React, { Component } from 'react';
import SliderBar from '../components/SliderBar';
import {Route,Switch} from 'react-router-dom';
import Add from './Add'
import UserDetail from './UserDetail'
import List from './List'
export default class User extends Component {
state = {
// 二级路由地址和标题
sliderBarData: [
{ path: '/user/add', content: '用户添加' },
{ path: '/user/list', content: '用户list' },
]
}
render() {
return (
{/* 二级菜单 默认展示添加路由 */}
//当点击user路径的时候默认展示Add组件的内容。这样不会当我们点击user路径的时候页面空着
///user/detail/:uid 路径参数
)
}
}
SliderBar.js 二级导航
import React, { Component } from 'react';
import { Link} from 'react-router-dom'
export default class SliderBar extends Component {
constructor() {
super();
}
render() {
return ()
}
}
Add.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
export default class Add extends Component {
input = React.createRef();
constructor() {
super();
}
handleSubmit = (e) => {
e.preventDefault(); // 阻止默认行文
let username = this.input.current.value;
let lists = JSON.parse(localStorage.getItem('lists'))|| [];
lists.push({username,id: Math.random()});
localStorage.setItem('lists', JSON.stringify(lists));
// 使用路由容器后 路由容器上挂载着一些属性 Provider history..
// Route组件中可以获取到 父级提供的属性,Route来消费 并且把这些属性传递给了渲染的组件
this.props.history.push('/user/list'); //跳转到 list页面
}
render() {
return (
)
}
}
List.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {Link} from "react-router-dom";
export default class List extends Component {
state = {
users: JSON.parse(localStorage.getItem('lists')) || [] //取app.js 添加的数据
}
render() {
return (
id
name
{this.state.users.map((user,index)=>{
return
{user.id}
//如果不传state数据可以直接这样:
// {user.id}
{user.username}
})}
)
}
}
UserDetail.js 二级内容 当点击list的时候进入,展示id和内容
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
export default class UserDetail extends Component{
constructor(){
super();
}
render(){
return (
UserDetail
//浏览器的地址 真实的 去到id
{/* /user/detail/1 /user/detail/:id => id:1 */}
//拿到当前路径的参数
{this.props.match.params.uid}
{/* 如果没拿到状态 就在获取一遍 通过id*/}
{this.props.location.state} //拿到传入的数据
)
}
}
过程
方法1
修改App.js
import React,{Component} from "react";
import ReactDOM from "react-dom";
import {Route} from "react-router-dom";
import Nav from "./nav";
export default class App extends Component{
constructor(){
super();
}
render(
return(
// 改为
//这样可以使 Nav下面的所有导航都可以有history
//所有用Route 渲染的组件 都有history
{this.props.children}
)
)
}
方法2
把App.js 复原
import React,{Component} from "react";
import ReactDOM from "react-dom";
import Nav from "./nav";
export default class App extends Component{
constructor(){
super();
}
render(
return(
{this.props.children}
)
)
}
Nav.js修改
import React, { Component } from 'react';
import { NavLink, Route, withRouter } from 'react-router-dom';
import MenuLink from './MenuLink';
//希望给当前组件带上一个Route,模拟的
// let withRouter = (Component) => {
// return ()=>{
// return
// }
// }
// 高阶组件 就是组件返回组件 ,可以把公共的功能放到父亲来做
// 封装公共方法的组件
class Nav extends Component {
constructor() {
super();
}
handleClick = () => {
this.props.history.push('/')
}
render() {
return (
)
}
}
// 如果某个组件 不是通过route来渲染的还想用里面的props 可以使用withRouter
export default withRouter(Nav); // 可以改写成 @withRouter的形式
需求:判断用户是否登入,没有登入则跳转到登入页面,
login.js
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
export default class Login extends Component{
constructor(){
super();
}
render(){
return (
)
}
}
给index.js 添加login
import Login from './Login';
给nav.js 添加login导航
登录
import React,{Component} from 'react';
import { Route,Redirect} from 'react-router-dom';
// 函数组件 参数是属性
// 把component 拿出来 重新命名Component 组件名必须大写
// props就是其他属性
// route中可以放置 component
// render render可以放一个函数 他会渲染这个函数的返回值
let Protected = ({component:Component,...props})=>{
return { // p=> history,match,lication
return localStorage.getItem('login') ? :
}}/>
}
export default Protected
修改index.js
import Protected from './Protected'
render(
{/* switch 会判断path */}
{/* 高阶组件中判断用户是否登录过,如果没登陆跳转 Protected */}
, window.root)