react--dva

DVA简介

之前用CRA这个脚手架进行react项目开发,react-router-dom / redux / react-redux / redux-thunk等

什么是DVA:就是一个轻量级的数据流框架 (主要是redux、redux-saga 也有路由、异步请求模块等)

DVA安装

步骤1:安装脚手架dva-cli

npm i dva-cli -g
或
yarn add global dva-cli

步骤2:验证是否安装成功

dva -v

DVA创建项目

步骤1:通过脚手架工具生成dva框架代码

dva new dvashop

步骤2:启动测试

cd dvashop

yarn start
或者
npm start

DVA路由

创建login路由

步骤1:定义路由 src/router.js文件

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './routes/IndexPage';
import LoginPage from './routes/LoginPage';

function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
        <!--配置路由,将路由与视图组件进行映射-->
        <Route path="/login" exact component={LoginPage} />
      </Switch>
    </Router>
  );
}

export default RouterConfig;

步骤2:创建组件 src/routes目录下创建

import React, { Component } from 'react'

class LoginPage extends Component {
    render() {
        return (
            <div>
                <h1>this is Login</h1>
            </div>
        )
    }
}

export default LoginPage

声明式导航

import {NavLink as Link} from "dva/router"
{/* 通过声明式导航的方式实现路由跳转 */}
<p><Link to="/login">进入登录页面</Link></p>

编程式导航

<p><button onClick={this.back}>回到首页</button></p>
back = ()=>{
        //通过编程式导航的方式实现路由跳转 
        this.props.history.push("/")
    }

因为LoginPage是路由组件,所以它的属性上面就会有路由相关的api。

但是如果某个组件不是路由组件?需要通过引入高阶组件withRouter,将普通组件变成伪路由组件,这样的话,上面也会有路由相关的api属性了。

(HOC高阶组件: 本质上就是一个函数,接受一个组件,最终返回一个新组件,可以给新组件上面传递额外的属性。)

connect()(UIComponent)

React.memo(functional component)

withRouter(Component)

切换路由模式

实现

步骤1:安装

yarn add history

步骤2:修改src/index.js 入口文件

import {createBrowserHistory as createHistory} from 'history';
const app = dva({
  history: createHistory(),
});

DVA模型models

定义与激活models

需求:定义购物车路由 它的模型里面定义redux的状态 num:666

实现

a.定义cars数据模型 src/models/cars

export default  {

    //定义命名空间,后续取redux状态的时候,通过此命名空间取值   
    namespace: 'cars',
    state: {
        num:666
    },
}

b. 激活cars数据模型

import Cars from "./models/cars"

app.model(Cars)

使用models

直接使用connect高阶组件

原理:react-redux被dva封装 从这里面导出connect

代码

import React, { Component } from 'react'
import { connect } from 'dva';   // connect其实就是dva封装了react-redux里面的

class CarsPage extends Component {
    render() {
        return (
            <div>
                <h1>this is Cars</h1>
                <h1>购物车( {this.props.num} )</h1>
            </div>
        ) 
    }
}

const mapStateToProps = state => {
    console.log('在cars组件中打印状态树数据', state)
    return {
        num: state.cars.num
    }
}

// export default CarsPage
export default connect(mapStateToProps)(CarsPage)

更新models

步骤1:修改redux状态,需要单独定义reducers

export default {
    
  // 一定要留心因为dispatch触发就是根据它
  // 命名空间
  namespace: 'cars',

  // 状态数据
  state: {
      num: 666
  },

  // action更新state
  reducers: {
    // 函数(state, action) {}  
    // 深拷贝
    setNum(state, action) {
      // 深拷贝
      let _state = JSON.parse(JSON.stringify(state))
      // 更新(默认的值+传递过来的值
      _state.num += action.payload.num
      // 返回
      return _state
    }
  },
}

步骤2:触发reducers中的方法

import React, { Component } from 'react'
import { connect } from 'dva';   // connect其实就是dva封装了react-redux里面的

class CarsPage extends Component {
    render() {
        return (
            <div>
                <h1>this is Cars</h1>
                <h1>购物车( {this.props.num} )</h1>
                <button onClick={()=>{
                    this.props.dispatch({  //通过dispatch派发action对象给reducer进行处理
                        // 命名空间/reducers名字
                        type: 'cars/setNum',
                        payload: {num:1}
                    })
                }}>更新+1</button>

                <button onClick={()=>{
                    this.props.dispatch({
                        // 命名空间/reducers名字
                        type: 'cars/setNum',
                        payload: {num:2}
                    })
                }}>更新+2</button>
            </div>
        ) 
    }
}

const mapStateToProps = state => {
    console.log('在carts组件中打印状态树数据', state)
    return {
        num: state.carts.num
    }
}

// export default CartsPage
export default connect(mapStateToProps)(CartsPage)

DVA模型effects

明确概念

手册:https://dvajs.com/knowledgemap/#effect

effects 异步处理

put 用户触发action 给reducer处理

call 用于调用异步函数

练习

effects 就是异步请求 拿到数据之后,通过 reducers来更新

内部安装了redux-saga , 要求我们进行异步操作的函数放入到effects中进行定义,都是generator形式的函数。

1 触发effects 通过console.log输出就行

   effects: {
        //es6中的generator函数  (async await)
        *demoAsync({ payload }, { call, put }) {  // eslint-disable-line
            yield console.log("触发了demoAsync这个异步方法...",payload)
        },
    },
<p><button onClick={()=>{
                    this.props.dispatch({
                        type:"cars/demoAsync",
                        payload:{
                            a:100
                        }
                    })
                }}>触发demoAsync异步方法</button></p>

2 触发effects 更新num (暂时不用异步请求

effects: {
        //es6中的generator函数  (async await)
        //call是可以进行异步调用
        //put是用于触发 action , 更改redux状态
        *demoAsync({ payload }, { call, put }) {  // eslint-disable-line
            yield put({type:"setNum",payload:{num:payload.a}})
        },
    },

3 触发effects 异步请求(这是咱们最终想完成的需求

state: {
    num:666,
    films:[]
},
reducers: {
    setFilms(state,action){
        return {
            ...state,
            films:action.payload.films
        }
    }
},
effects: {
        //es6中的generator函数  (async await)
        //call是可以进行异步调用
        //put是用于触发 action , 更改redux状态
        *setFilmsAsync({ payload }, { call, put }){
            //call异步请求获取数据
            let data = yield call(getFilmsData);
            //put去触发action提交给reducer,从而实现更改redux状态
            yield put({type:"setFilms",payload:{films:data.data.data.films}})
        }
},

service/cars.js

import request from '../utils/request';

export function getFilmsData() {
  return request('https://m.maizuo.com/gateway',{
    headers:{
      'X-Client-Info': '{}',
      'X-Host': 'mall.film-ticket.film.list'
    }
  });
}

CarsPage

const mapState = state=>{
    return {
        num:state.cars.num,
        films:state.cars.films
    }
}

DVA模型subscriptions

models/login

export default {
    namespace: 'login',
    state:{},
    reducers:{},
    subscriptions: {
        //初始化的时候只要进入登录页面就会触发cars/setFilmsAsync
        setup({ dispatch, history }) {
          history.listen(({ pathname }) => {
            if (pathname === '/login') {
              dispatch({
                type: 'cars/setFilmsAsync',
              });
            }
          });
        },
    },
}
app.model(require('./models/login').default);   

DVA周边roadhog

简介

是什么:是一个命令行工具,相当于dva版的webpack(相对比较简单

能干嘛:配置多页面、CSS预处理、前端代理等操作

去哪下:不用下,因为集成在dva里面

仓库地址:https://github.com/sorrycc/roadhog/blob/master/README_zh-cn.md

配置(单入口分析

默认:打包index.js -> public/index.html自定引入(原理就是咱们昨天讲的HTML插件

现在:实现多入口 增加about.js通过about.html可以访问其内容

实现:

步骤1:创建src/about.js

// console.log('hello,webopenfather')

import React, { Component } from 'react'
import {render} from 'react-dom'

class About extends Component {
    render() {
        return (
            <div>
                <h1>this is about page</h1>
            </div>
        )
    }
}

render(<About />, document.querySelector('#root'))

步骤2:创建about.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>测试多入口About</title>
  <link rel="stylesheet" href="index.css" />
</head>
<body>

  <div id="root"></div>
  <script src="about.js"></script>

</body>
</html>

步骤3:.webpackrc配置多入口

"entry": {
        "index": "./src/index.js",
        "about": "./src/about.js"
    }

配置(CSS模块化

明确:roadhog可以简单简单理解为基于webpack封装

然后:和cra一样css、less都默认直接可以使用

import stylesLess from './LoginPage.less';

<div className={`${stylesLess.main} ${styles.aaa}`}>

配置(跨域

练习:

发现跨域报错

解决

export function getDoubanData(){
  return request("http://47.96.0.211:9000/db/in_theaters")
}
effects:{
      *getDataAsync({payload},{call,put}){
        let data = yield call(getDoubanData)
        console.log("data===>",data)
      }
    }

<p><button onClick={()=>{
    this.props.dispatch({
    	type:"login/getDataAsync"
    })
}}>请求getDataAsync</button></p>


export default connect()(LoginPage)

webpackrc配置文件配置代理:

"proxy": {
        "/api": {
            "target": "http://47.96.0.211:9000",
            "changeOrigin": true,
            "pathRewrite": { "^/api" : "" }
        } 
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值