dva简化了我们组件之间的数据通信(简化了我们之前在组件传值的时候使用的redux)
通过dva 就可以让我们更好的执行项目中数据传递的一个便捷性
dva=react-router(虽然dva中带有路由功能 可能工作中一般是吧dva和umi配合使用)+redux+redux-saga
简化完成一个redux的闭环 (dva和redux不是一个东西 他是redux的替代产品)
redux-saga是在redux中完成异步操纵的一个技术
npm install -g dva-cli 全局下载
dva -v 查看版本
cd到指定文件夹下
dva new 项目名 创建项目
npm start 启动项目
dva中也带路由功能 但是 在实际开发的时候 很多开发者喜欢把umi和dva整合在一起 umi管理路由 dva进行组件传值 各干各的事
1.创建路由组件页面
在src文件夹下的routes文件夹下创建即可
2.配置 在src下找到router.js进行配置
import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './routes/IndexPage';
// 1.引用
import Home from './routes/home';
import Phone from './routes/phone';
function RouterConfig({ history }) {
return (
<Router history={history}>
<Switch>
<Route path="/" exact component={IndexPage} />
{/* 2.配置规则 */}
<Route path="/home" exact component={Home} />
<Route path="/phone" exact component={Phone} />
</Switch>
</Router>
);
}
export default RouterConfig;
import {Link} from "dva/router"
export default ()=>{
return (
<>
<Link to="/">默认页面</Link>
<Link to="/home">home</Link>
<Link to="/phone">phone</Link>
</>
)
}
编程式的方式和原生react的react-router-dom实现路由的方式是一样的
也要使用withRouter来设置不是被路由所管理的页面 具有路由的跳转对象
import {Link,withRouter} from "dva/router"
let Topbar= (props)=>{
let fun=()=>{
// 编程式导航
props.history.push("/phone")
}
return (
<>
<Link to="/">默认页面</Link>
<Link to="/home">home</Link>
<Link to="/phone">phone</Link>
<button onClick={fun}>点我进行页面的跳转phone</button>
</>
)
}
export default withRouter(Topbar)
model就是用来存放一个个的小模块 通过模块化的管理 可以弱化 组件数据与组件数据的耦合度
1.在src下的models文件夹下创建属于我们自己的数据模块
// 创建了一个phone组件的状态模块
export default {
namespace: 'phonem',//命名空间 给当前这个模块起个名字必须写
state: {//管理数据的
},
};
2.使用模块
把模块文件在index.js中进行配置引用
import dva from 'dva';
import './index.css';
// 1. Initialize
const app = dva();
// 2. Plugins
// app.use({});
// 3. Model
// app.model(require('./models/example').default);
app.model(require('./models/phonem.js').default);
// 4. Router
app.router(require('./router').default);
// 5. Start
app.start('#root');
3.组件内使用配置的模块
在组件内使用connect()高阶组件 来进行连接
import React, { Component } from 'react'
import Tb from "../components/topbar"
// 1.引用connect connect是一个高阶组件
import {connect} from "dva"
class phone extends Component {
render() {
return (
<div>
<Tb/>
phone
{/* 读取模块中的数据 */}
{/* {this.props.state.命名空间.数据} */}
{this.props.state.phonem.name}
</div>
)
}
}
// connect是一个方法 只有这个方法被调用的时候才是一个高阶组件
export default connect(state=>({state}))(phone)
state就是dva中的数据源 把所有的数据都存放在state中
// 创建了一个phone组件的状态模块
export default {
namespace: 'phonem',//命名空间 给当前这个模块起个名字必须写
state: {//管理数据的
name:"xixi",
age:18,
arr:[1111,2222,3333,4444,5555]
},
};
在dva的model中 我们使用reducers可以进行数据的修改操作
reducers中包含的就是一个个的函数 每一个函数就是一个修改的动作
export default {
namespace: 'homem',
state: {
name:"xixi",
age:18
},
// 数据修改
reducers:{
// 每一个函数就是一个数据的修改动作
demoa(){
},
demob(){
},
}
};
1.创建修改
export default {
namespace: 'homem',
state: {
name:"xixi",
age:18
},
// 数据修改
reducers:{
// 每一个函数就是一个数据的修改动作
// state 数据源
// payload 就是外部传递进来的数据
demoa(state,payload){
// 在函数中返回一个修改之后的结果
return {...state,age:666}
},
demob(){
},
}
};
2.组件中触发这个修改的动作
this.props.dispatch({type:“命名空间的名字/你要调用的reducers的名字”})
import React, { Component } from 'react'
import {connect} from "dva"
class home extends Component {
fun=()=>{
// 调用dva中的reducers进行数据的修改
this.props.dispatch({type:"homem/demoa"})
}
render() {
return (
<div>
我是dva---{this.props.state.homem.name}
{this.props.state.homem.age}
<button onClick={this.fun}>点我修改age</button>
</div>
)
}
}
export default connect(state=>({state}))(home)
payload就是用来接受调用的时候传递进来的数据
1.传递数据的时候 在dispatch的方法中传递第二个参数
import React, { Component } from 'react'
import {connect} from "dva"
class home extends Component {
fun=()=>{
// 调用dva中的reducers进行数据的修改
this.props.dispatch({type:"homem/demoa"})
}
funb=()=>{
// 我给reducers的payload传递数据
this.props.dispatch({type:"homem/demob",data:{text:"我是传递的数据"}})
}
render() {
return (
<div>
我是dva---{this.props.state.homem.name}
{this.props.state.homem.age}
<button onClick={this.fun}>点我修改age</button>
<button onClick={this.funb}>点我传递payload</button>
</div>
)
}
}
export default connect(state=>({state}))(home)
2.在模块中可以使用payload来进行数据的接收
export default {
namespace: 'homem',
state: {
name:"xixi",
age:18
},
// 数据修改
reducers:{
// 每一个函数就是一个数据的修改动作
// state 数据源
// payload 就是外部传递进来的数据
demoa(state,payload){
// 在函数中返回一个修改之后的结果
return {...state,age:666}
},
demob(state,payload){
// console.log(payload.data)
return {...state,age:payload.data.text}
},
}
};
1.在services下 设置我们的请求封装
import request from '../utils/request';
export function query() {
return request('/api/users');
}
//我们自己的请求
export function apilink() {
return request('http://localhost:3000/user/list');
}
2.在想使用请求的组件中 引用 使用
import React, { Component } from 'react'
import {connect} from "dva"
// 引用请求封装
import {apilink} from "../services/example.js"
class home extends Component {
fun=()=>{
// 调用dva中的reducers进行数据的修改
this.props.dispatch({type:"homem/demoa"})
}
funb=()=>{
// 我给reducers的payload传递数据
this.props.dispatch({type:"homem/demob",data:{text:"我是传递的数据"}})
}
func=()=>{
// 请求数据
apilink().then((ok)=>{
console.log(ok)
})
}
render() {
return (
<div>
我是dva---{this.props.state.homem.name}
{this.props.state.homem.age}
<button onClick={this.fun}>点我修改age</button>
<button onClick={this.funb}>点我传递payload</button>
<hr />
<button onClick={this.func}>点我发送请求</button>
</div>
)
}
}
export default connect(state=>({state}))(home)
当我们运行的时候发现请求会跨域
在dva中设置跨域 我们在webpackrc的文件中进行设置
写的内容同vue于react的跨域内容 使用proxy来进行跨域解决
{
"proxy":{ //设置devServe解决跨域问题
"/api":{
// 我们需要告诉devserver帮我们解决那个地址的跨域
"target":"http://localhost:3000/",
"changeOrigin":true,
"ws":true,
// 替换地址
"pathRewrite":{
"^/api":""
}
}
}
}
千万不要忘了 把请求地址换成 /api 重启项目
effect中是一个个的函数 每个函数就是一个异步操作
Generator 有的人叫做迭代器函数 / 星号函数
通过generator函数 可以让我们在函数执行的时候 控制其内容的内容 走走停停 让函数交出执行权 可以让函数在调用的时候按照我们的需要执行或者暂停
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function fun(){
console.log(1)
console.log(2)
console.log(3)
}
fun()
// 在传统的函数中 只要函数被调用 那么函数中的所有代码
// 都会从上到下 一次执行一遍
</script>
</body>
</html>
我现在不想让函数一调用全部都执行 我想让他按照我的命令来执行怎么办?
可以让我们在函数执行的时候 控制其内容的内容 走走停停 让函数交出执行权 可以让函数在调用的时候按照我们的需要执行或者暂停
要求
1.在生命函数点的时候 在 函数名前面加一个*号 用于区分和普通函数的区别
2.yield 分割线 通过分割线就可以指明我们需要函数在执行中的暂停位置
3.使用next()来执行函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function *fun(){
console.log(1)
yield
console.log(2)
yield
console.log(3)
}
// console.log(fun())
// 我们需要使用next()让他走走停停
let g=fun()
g.next()//执行
g.next()//执行
g.next()//执行
</script>
</body>
</html>
是吧数据请求在effect中进行数据请求 然后把请求来的数据交给 reducers进行修改 最终赋值给state
1.需要在页面有个事件触发 effects进行异步操作
this.props.dispatch({type:“命名空间的名字/你触发effects的名字”})
import React, { Component } from 'react'
import {connect} from "dva"
class phone extends Component {
componentDidMount() {
// 触发effects进行数据请求
this.props.dispatch({type:"homem/demolink"})
}
render() {
return (
<div>
<h1>dva数据请求闭环操作</h1>
</div>
)
}
}
export default connect(state=>({state}))(phone)
2.就在模块中创建对应的effects
export default {
namespace: 'homem',
state: {
name:"xixi",
age:18
},
// 数据修改
reducers:{
// 每一个函数就是一个数据的修改动作
// state 数据源
// payload 就是外部传递进来的数据
demoa(state,payload){
// 在函数中返回一个修改之后的结果
return {...state,age:666}
},
demob(state,payload){
// console.log(payload.data)
return {...state,age:payload.data.text}
},
},
// 进行异步数据的操作
effects:{
// 对应的都是一个个的方法(Generator函数) 每个方法都是一个异步数据的操作
*demolink({payload},{put,call}){
}
}
};
3.在刚才创建的effect中进行异步操作
// 引用请求封装
import {apilink} from "../services/example.js"
export default {
namespace: 'homem',
state: {
name:"xixi",
age:18
},
// 数据修改
reducers:{
// 每一个函数就是一个数据的修改动作
// state 数据源
// payload 就是外部传递进来的数据
demoa(state,payload){
// 在函数中返回一个修改之后的结果
return {...state,age:666}
},
demob(state,payload){
// console.log(payload.data)
return {...state,age:payload.data.text}
},
},
// 进行异步数据的操作
effects:{
// 对应的都是一个个的方法(Generator函数) 每个方法都是一个异步数据的操作
*demolink({payload},{put,call}){
// 先把请求引用进来
// 使用请求call 用来包裹数据请求 会返回出成功的结果
let data=yield call(apilink)
console.log(data)
}
}
};
4.把请求来的数据交给reducers进行state的修改
// 引用请求封装
import {apilink} from "../services/example.js"
export default {
namespace: 'homem',
state: {
name:"xixi",
age:18
},
// 数据修改
reducers:{
// 每一个函数就是一个数据的修改动作
// state 数据源
// payload 就是外部传递进来的数据
demoa(state,payload){
// 在函数中返回一个修改之后的结果
return {...state,age:666}
},
demob(state,payload){
// console.log(payload.data)
return {...state,age:payload.data.text}
},
},
// 进行异步数据的操作
effects:{
// 对应的都是一个个的方法(Generator函数) 每个方法都是一个异步数据的操作
*demolink({payload},{put,call}){
// 先把请求引用进来
// 使用请求call 用来包裹数据请求 会返回出成功的结果
let data=yield call(apilink)
console.log(data.data.data)
// 把请求来的数据交给reducers来修改 我们在effect中调用reducer使用put来触发
yield put({
type:"update",//put是调用reducer的 type就是调用的reducer名字
data:{
arr:data.data.data
}
})
}
}
};
5.编写对应的reducer 来进行state的修改
// 引用请求封装
import {apilink} from "../services/example.js"
export default {
namespace: 'homem',
state: {
name:"xixi",
age:18,
arr:[]
},
// 数据修改
reducers:{
// 每一个函数就是一个数据的修改动作
// state 数据源
// payload 就是外部传递进来的数据
demoa(state,payload){
// 在函数中返回一个修改之后的结果
return {...state,age:666}
},
demob(state,payload){
// console.log(payload.data)
return {...state,age:payload.data.text}
},
// 进行state的数据修改
update(state,payload){
return {...state,arr:payload.data.arr}
}
},
// 进行异步数据的操作
effects:{
// 对应的都是一个个的方法(Generator函数) 每个方法都是一个异步数据的操作
*demolink({payload},{put,call}){
// 先把请求引用进来
// 使用请求call 用来包裹数据请求 会返回出成功的结果
let data=yield call(apilink)
console.log(data.data.data)
// 把请求来的数据交给reducers来修改 我们在effect中调用reducer使用put来触发
yield put({
type:"update",//put是调用reducer的 type就是调用的reducer名字
data:{
arr:data.data.data
}
})
}
}
};
6页面获取数据
import React, { Component } from 'react'
import {connect} from "dva"
class phone extends Component {
componentDidMount() {
// 触发effects进行数据请求
this.props.dispatch({type:"homem/demolink"})
}
render() {
return (
<div>
{/* 读取数据 */}
<h1>dva数据请求闭环操作---{this.props.state.homem.arr}</h1>
</div>
)
}
}
export default connect(state=>({state}))(phone)