路由守卫
1- 全局守卫
--- MyRouter.jsx
import React, { Component } from 'react' import {Route,Redirect} from 'react-router-dom' export default class myRouter extends Component { render() { // 获取用户登录信息 let userInfo = JSON.parse(localStorage.getItem('userInfo')||'{}') return ( <> {/* 判断是否有token, 已登录时可以使用路由规则的,未登录时重定向到登录页面 */} {userInfo.token?<Route path={this.props.path} component={this.props.component}></Route>:<Redirect to='/login'></Redirect>} </> ) } }
-- app.js
<Switch> {/* 路由规则 */} <Route path='/login' component={Login}></Route> {/* 也需要登录拦截 */} {/* <Route path='/food' component={Food}></Route> */} <MyRouter path='/food' component={Food}></MyRouter> {/* 登录之后可以访问 */} {/* <Route path='/index' component={Index}></Route> */} <MyRouter path='/index' component={Index}></MyRouter> {/* 路由重定向 */} <Redirect exact from='/' to='/index'></Redirect> {/* 404页面 */} <Route component={Not}></Route> </Switch>
2- 独享守卫
{/* 独享守卫 */} <Route path="/movie" render={()=>{ if(JSON.parse(localStorage.getItem('userInfo')||'{}').type==='2'){ return <Movie></Movie> }else{ // return <h1>请开通vip</h1> return <Redirect to='/login'></Redirect> } }}></Route>
数据请求
1- 跨域:服务器代理
1- package.json
"proxy":"http://localhost:3000"
2-借助 http-proxy-middleware
-
安装
npm i http-proxy-middleware
-
创建文件 src/setupProxy.js
// 服务代理 const proxy = require('http-proxy-middleware') module.exports = (app)=>{ // /api/getcate ---> http://localhost:3000/api/getcate // 如果接口不规律的url, 可以在url前拼接一个统一的字符, 根据字符做服务器代理 // /req/api/getcate ---> http://localhost:3000/req/api/getcate 路径重写 http://localhost:3000/api/getcate // 确定标识符 app.use('/req',proxy.createProxyMiddleware({ target:'http://localhost:3000', //路径重写 pathRewrite:{ '/req':'' } })) }
2- axios
-
安装
npm i axios --save
-
引入
import axios from 'axios'
-
使用
axios() axios.get() axios.post() qs.stringify()
详细介绍请参考第8天笔记
3- fetch
fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。fetch有很多优势:①语法简介,更加语义化。②基于标准Promise实现,支持async/await。③提供了丰富的API④脱离了XHR。fetch是一种HTTP数据请求的方式,在react中,数据交互仍然使用axios
3-1 get
fetch('url',配置项).then(res=>res.json()).then(res=>{})
-
第一个then接收的是时响应对象
-
第二个then接收数据
1- 无参数时
// fetch获取分类列表 fetch('req'+'/api/getcate',{ headers:{ token:'123' } }).then(res=>res.json()).then(res=>{ // 第二个then接收到响应数据 console.log(res); })
2- 需要携带参数
参数需要是字符串拼接格式 cateid=5&type=1
componentDidMount(){ // fetch的get请求携带参数时 // qs处理参数 let qm = qs.stringify(this.state.obj) // {cateid:5,type:1} --> cateid=5&type=1 fetch('/req/api/getgoodlist?'+qm).then(res=>res.json()).then(res=>{ console.log(res); }) }
3-2 post
fetch('url',{ method:'post' ,body:{参数}}).then(res=>res.json()).then(res=>{})
post传参时,参数在body.
1- 参数没有文件时
qs.stringify()参数一定要序列化, 同时修改content-type: application/x-www-form-urlencoded
reg(){ // console.log(this.state.user); // 参数需要qs处理 fetch('/req/api/register',{ method:'post', // 传参时一定要修改content-type headers:{ 'content-type':'application/x-www-form-urlencoded' }, body:qs.stringify(this.state.user) }).then(res=>res.json()).then(res=>{ console.log(res); }) }
2- 参数有文件时
参数需要转为formdata ,不需要修改content-type
// 添加服装分类 add(){ console.log(this.state.cate); // 有文件,转为formdata let fm = new FormData() for(let key in this.state.cate){ fm.append(key,this.state.cate[key]) } fetch('/req/api/cateadd',{ method:'post', body:fm, }).then(res=>res.json()).then(res=>{ console.log(res); }) }
3-3 fetch的封装
---request/http.js
// fetch的二次封装 //引入qs import qs from 'querystring' let pre = '' // 判断生产环境和开发环境 if(process.env.NODE_ENV==='development'){ // 开发环境 pre='/req' } // 如果是生产环境 if(process.env.NODE_ENV==='production'){ pre='' } // url: 请求接口地址 // param: 参数 export let get = function(url,param={}){ // 处理参数 let data = qs.stringify(param) return new Promise((resolve,reject)=>{ fetch(pre+url+"?"+data).then(res=>res.json()).then(res=>{ // 抛出响应的数据 resolve(res) }) }) } // url: 请求接口地址 // param 参数对象 // isFile 是否有文件 true 有文件 export let post = function(url,param,isFile=false){ let data = null let headers={} if(isFile){ // 有文件 data = new FormData() for(let key in param){ data.append(key,param[key]) } }else{ //没有文件 data = qs.stringify(param) headers={ 'content-type':'application/x-www-form-urlencoded' } } return new Promise((resolve)=>{ fetch(pre+url,{ method:'post', body:data, headers:headers }).then(res=>res.json()).then(res=>{ resolve(res) }) }) }
---同一管理所有api request/api
// 统一管理所有的api import {get,post} from './http' // 获取分类 // export let getCate = function(){ // return get('/api/getcate') // } export let getCate = ()=>get('/api/getcate') // 用户注册 export let register = (data)=>post('/api/register',data)
3- redux
集中式状态管理
三大原则:
-
唯一的状态源
-
state是只读
-
纯函数修改状态
安装
npm i redux --save
创建 store/index.js
// 创建数据仓库 import {createStore} from 'redux' // 仓库的状态数据 let initState = { name:'小黑', age:20 } // 定义一个函数, // state: 上一次的状态.如果是第一次是没有上一次状态的 // action: 自定义的规则, {type:'changeName',name:'小白'}, {type:'changeAge',age:99} function reducer(state=initState,action){ // if(actions.type==='changeName'){ // return { // ...state, // name:action.name // } // } // if(actions.type==='changeAge'){ // return { // ...state, // age:action.age // } // } switch(action.type){ case 'changeName': return { ...state, name:action.name } case 'changeAge': return { ...state, age:action.age } default: return { ...state } } } let store = new createStore(reducer) export default store
redux的方法
-
store.getState() 获取数据仓库状态
-
store.dispatch({}) 派发一个action,修改状态
-
let uns = store.subscribe() 添加一个监听,每次dispatch都会监测到
-
uns() 取消监听
import React, { Component } from 'react' import store from '../store' export default class One extends Component { componentDidMount(){ // 开启监听 store.subscribe(()=>{ // 更新视图 this.setState({}) }) } // 修改name change(){ // 派发action,修改state store.dispatch({type:'changeName',name:'小白'}) console.log(store.getState()); } render() { let {name,age} = store.getState() return ( <div className='box'> <h1>one组件</h1> {/* 获取数据仓库状态 */} <h2>name: {store.getState().name} </h2> <button onClick={()=>this.change()}>修改name</button> </div> ) } }