react 路由守卫+数据请求(跨域,axios,fetch)+redux

路由守卫

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>
        )
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值