路由、状态管理

内容:路由、状态管理

日期:2020-09-14

一、路由

react也是spa单页面应用

1.安装

npm i react-router-dom --save

2.基本使用

(1)在/src/index.js引入路由模式

import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(<BrowserRouter><App /></BrowserRouter>,document.getElementById('root'));

(2)创建几个页面组件,此处省略

(3)在/src/App.js中引入Switch、Route组件和需要展示的页面组件

import React from 'react';
import { Switch,Route } from 'react-router-dom'//引入需要的路由相关组件
import Home from './Home'//引入页面组件
import Login from './Login'
function App() {
    return (
        <div className="App">
            {/* Switch相当于vue-router中的router-view */}
            <Switch>
                {/* Route是react中的路由配置规则 */}
                <Route path="/home" component={ Home }></Route>
                <Route path="/login" component={ Login }></Route>
            </Switch>
        </div>
    );
}
export default App;

3.路由模式

BrowserRouter 是history模式

HashRouter是hash模式

在/src/index.js中引入hash模式

import { HashRouter } from 'react-router-dom'
ReactDOM.render(<HashRouter><App /></HashRouter>,document.getElementById('root'));

4.路由重定向

Redirect

import { Switch,Route,Redirect } from 'react-router-dom'
<Switch>
    {/* Route是react中的路由配置规格 */}
    <Route path="/home" component={ Home }></Route>
    <Route path="/login" component={ Login }></Route>
    {/* Redirect是重定向的组件
    	path属性的值为星号,表示前面所有的路由规则都没有匹配到 
    	to属性的值为具体的某一个路由规则的path属性值
    */}
    <Redirect path="*" to="/home"></Redirect>
</Switch>

5.路由导航

(1)内置组件

Link 会生成a标签,需要设置to属性,但是它没有激活状态的类名

NavLink 会生成a标签,需要设置to属性,它有激活状态的类名

引入导航组件

import { Switch,Route,Redirect,Link,NavLink } from 'react-router-dom'

使用导航组件

<Link to="/home">首页</Link>
<Link to="/login">登录</Link>
<hr/>
<NavLink to="/home">首页</NavLink>
<NavLink to="/login">登录</NavLink>
(2)编程式导航

当使用了react-router-dom路由后,在页面组件的props.history中封装一些可以使用方法,进行页面跳转,其中push、replace、go的用法和vue-router中一样

push

replace

go 需要传递参数,一般写-1,表示回退到上一个页面

goBack 不需要传递参数,直接回退到上一个页面

6.路由嵌套

需要在哪个页面展示不同的内容,就在哪个页面组件中引入Switch、Route来设置路由出口并定义路由规则。

(1)在src/App.js中定义一级路由规则

<Switch>
    {/* Route是react中的路由配置规格 */}
    <Route path="/home" component={ Home }></Route>
    <Route path="/login" component={ Login }></Route>
    <Redirect path="*" to="/home"></Redirect>
</Switch>

(2)在右侧展示的页面组件中定义二级路由规则

import React from 'react'
import { Switch,Route } from 'react-router-dom'
import Menu from './Menu'//引入左侧菜单组件
//引入需要在右侧展示的页面组件
import Student from '../pages/Student'
import Setting from '../pages/Setting'
import User from '../pages/User'
export default ()=>{
    return(
        <div className="middle">
            <Menu></Menu>
            <div className="right">
                <Switch>
                    <Route path="/home/student" component={ Student }></Route>
                    <Route path="/home/setting" component={ Setting }></Route>
                    <Route path="/home/user" component={ User }></Route>
                </Switch>
            </div>
        </div>
    )
}

7.高阶组件

如果某个组件不是通过路由渲染出来的,在这个组件中是没有路由相关的信息的

withRouter,可以让页面组件的组成部分组件获取对应的路由信息

import React, { Component } from 'react'
//引入withRouter组件
import { NavLink,withRouter } from 'react-router-dom'
class Menu extends Component {
    logout(){
    	this.props.history.push('/login')
    }
    render() {
        return (
            <div className="menu">
                <NavLink to="/home/student">学生管理</NavLink>
                <NavLink to="/home/setting">系统设置</NavLink>
                <NavLink to="/home/user">个人中心</NavLink>
                <button onClick={ ()=>this.logout() }>退出</button>
            </div>
        )
    }
}
//使用withRouter组件包含当前组件
export default withRouter(Menu);

8.路由传参

(1)动态路由

第一步:创建一个详情页面

第二步:定义一个动态路由规则

exact 精确匹配,默认是模糊匹配,需要给具体的路由规则添加exact属性设置为精确匹配

<Route exact path="/home/student" component={ Student }></Route>
<Route path="/home/student/:sid" component={ StudentInfo }></Route>

第三步:在列表页面通过编程式导航跳转到详情页面

this.props.history.push('/home/student/'+id);

第四步:在详情页面获取动态路由参数

<p>学生编号:{ this.props.match.params.sid }</p>
(2)查询参数

如果路由传递的参数数量不固定时,使用动态路由就不合适了,可以使用查询参数的方式来进行数据的传递。

第一步:定义一个固定的路由规则

<Route path="/home/student/info" component={ StudentInfo }></Route>

第二步:在列表页面通过编程式导航进行页面跳转并传递参数

使用querystring插件

npm i querystring --save

使用querystring插件

import qs from 'querystring'
 toInfo(obj){
 // this.props.history.push('/home/student/'+id);
     this.props.history.push({
         pathname:'/home/student/info',
         search:"?"+qs.stringify(obj)//qs.stringify把对象转换成字符串
     })
 }

第三步:在详情页面获取数据

var search = this.props.location.search.substr(1);//把参数中的问号去掉
// querystring parse 把 参数名=参数值&参数名N=参数值N 格式的数据转换成对象
var obj = qs.parse(search);//qs.parse把字符串转换成对象

二、状态管理

1.flux

React 标榜自己是 MVC 里面 V 的部分,那么 Flux 就相当于添加 M 和 C 的部分。

Flux 是 Facebook 使用的一套前端应用的架构模式。

流程:

view 触发action

action通知dispatcher(派发器)

dispatcher通知仓库修改状态

store仓库修改完状态后,通知页面进行重新渲染

安装:

npm i flux --save

第一步:创建仓库

/src/store/index.js

let state = {
	name:'flux name',
	age:18
}
export default { state }

第二步:在页面组件中引入仓库,并使用仓库中的数据

import React, { Component } from 'react'
import store from '../store'
export default class Setting extends Component {
	render() {
        return (
            <div>
                <h1>系统设置页面</h1>
                <h3>仓库中的name为:{ store.state.name }</h3>
            </div>
        )
    }
}

此时只能从仓库中获取数据

第三步:如果想通过页面发起一个事件,来修改仓库中的数据。

从flux中引出Dispatcher派发器,并注册好派发任务,用来修改数据

/src/store/index.js

import { Dispatcher } from 'flux'
let state = {
	name:'flux name',
	age:18
}
let dispatcher = new Dispatcher();
dispatcher.register(action=>{
	switch(action.type){
		case "changeName":
			state.name = action.params
			break;
		default:
			break;
	}
})
export default { state,dispatcher }

action是一个形参,action.type是自定义的一个属性,用来判断要执行什么样的数据操作

​ action.params是自定义的一个属性,用来接收数据

此时可以在页面组件中通过dispatcher来派发一个具体的任务,用来修改数据

import React, { Component } from 'react'
import store from '../store'
import User from './User'
export default class Setting extends Component {
    setName(){
        //通过派发器来派发一个具体的任务,并告知操作的类型及数据
        store.dispatcher.dispatch({
            type:'changeName',
            params:'hello,flux'
        })
    }
    render() {
        return (
            <div>
                <h1>系统设置页面</h1>
                <h3>仓库中的name为:{ store.state.name }</h3>
                <button onClick={ ()=>this.setName() }>修改</button>
                <User />
            </div>
        )
    }
}

此时,仓库中的数据会修改,但是页面中没有变化。

当仓库中的数据变化时,页面重新渲染

/src/store/index.js引入事件监听器

// 引入派发器
import { Dispatcher } from 'flux'
// 引入事件监听器(仓库数据变化后,页面也跟着重新渲染)
import EventEmitter from 'events'
class State extends EventEmitter{
    name = 'flux name'
    age = 18
}
let state = new State();
//实例化派发器
const dispatcher = new Dispatcher();
//注册具体的派发任务
dispatcher.register(action=>{
    //根据传递的参数来执行不同的数据操作
    switch(action.type){
        case 'changeName':
            state.name = action.params;
            break;
        case 'changeAge':
            state.age = action.params;
            break;
        default:
            break;
    }
    //触发一个事件
    state.emit('change')
})
export default { state,dispatcher }

在页面组件的挂载完成钩子函数中用来监听仓库中的数据变化

import React, { Component } from 'react'
import store from '../store'
import User from './User'
export default class Setting extends Component {
    setName(){
        //通过派发器来派发一个具体的任务,并告知操作的类型及数据
        store.dispatcher.dispatch({
            type:'changeName',
            params:'hello,flux'
        })
    }
    componentDidMount(){
        //页面组件挂载完成后
        //通过仓库中的事件监听器进行监听,然后重新渲染页面
        store.state.on('change',()=>{
            this.setState({})
        })
    }
    render() {
        return (
            <div>
                <h1>系统设置页面</h1>
                <h3>仓库中的name为:{ store.state.name }</h3>
                <button onClick={ ()=>this.setName() }>修改</button>
                <User />
            </div>
        )
    }
}

2.redux

Redux由Dan Abramov在2015年创建的科技术语。是受2014年Facebook的Flux架构以及函数式编程语言Elm启发。很快,Redux因其简单易学体积小在短时间内成为最热门的前端架构。

Redux最主要是用作应用状态的管理。简言之,Redux用一个单独的常量状态树(对象)保存这一整个应用的状态,这个对象不能直接被改变。当一些数据变化了,一个新的对象就会被创建(使用actions和reducers)。

redux核心概念:

​ actions

​ store

​ reducers

redux三个原则:

​ 单一数据源

​ state是只读的

​ 使用纯函数修改state

(1)安装

npm i redux

(2)基本语法

流程:

​ 引入CreateStore

​ 定义初始状态

​ 定义纯函数

​ 定义仓库

示例代码:

①引入createStore

/src/store/index.js

import { createStore } from 'redux'

②定义初始状态

const initalState = {
    name:'小飞',
    age:18
}

③定义纯函数

state 上一次修改完成后的状态

action是组件dipatch的动作

reducer一定要返回一个新的state,否则就检测不到state的变化

function reducer( state = initalState,action ){
    switch(action.type){
        case 'changeName':
            return{
                ...state,
                name:action.params
            }
        case 'changeAge':
            return{
                ...state,
                age:action.params
            }
        default:
            return state;//一定要返回
    }
}

④创建仓库

const store = createStore(reducer);
export default store;

⑤页面组件使用状态

引入仓库

import store from './store'

使用仓库中的数据

<p>仓库中的name为:{ store.getState().name }</p>

⑥改变状态

changeName(){
    store.dispatch({
        type:'changeName',
        params:'小芳'
    });
}

⑦使用订阅者实现数据变化页面就变化

componentDidMount(){
    //仓库数据变化,想要重新渲染页面,就添加订阅者
    store.subscribe(()=>{
    	this.setState({})
    })
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值