dva简单理解(二)

models

dva 是 : React+Redux+webpack+babel+es6,这是一个极具生产力的组合
源自flux架构的单向流动使得应用的逻辑和数据流动变得可控,当应用逻辑变得复杂的时候,其优势越加明显,开发越加高效

但是在开发的时候出现了一些问题,比如说概念太多,文件太松散等等问题

以及为了解决异步交互问题,会引用一些中间件来处理store,比较常见的是用thunk中间件+asysc或者用saga等等



models:
namespace: key值 对应唯一的state
不同的state可以对应不同组件的状态管理
这样的话 是便于按需加载管理状态的 dynamic 就可以让每个路由按需加载对应的state
dynamic 是接收三个参数的
第一个参数:是实例app 可以 RouterConfig 中结构出来的
第二个参数: 就是model状态了, 其实看看出是以函数形式返回一个数组,里面元素就是状态model 说明可以有多个状态的
第三个参数: 就是对应的组件了
import React from 'react' ;
import { Router , Route , Switch , Redirect , routerRedux } from 'dva/router' ;
import Home from './routes/Index/IndexPage' ;
// import app from './index'

import List from "./routes/List/List.js" ;

import Login from "./components/Login.js" ;

import dynamic from 'dva/dynamic' //关键作用 用于每个路由模块的 按需加载 第一个参数 app : 是 需要挂载router的app实例 第二个参数是model : reducer仓库 第三个参数是component : 组件

const { ConnectedRouter }= routerRedux //将histrory 分发到所有的组件上
const routeArr = [
{
path: '/Home/List' ,
component : () => List , //必须是函数 返回组件
models : () => [ import ( './models/products' )], //必须是函数 返回一个数组
}, {
path: '/Login' ,
component : () => Login ,
models : () => [ import ( './models/Login' )],
}
]

function RouterConfig ({ history , app }) {
return (
< ConnectedRouter history = { history } >
< Home >
< Router history = { history } >
< Switch >
< Route path = "/" exact render = { () => < Redirect to = "/Login" /> } />
{
routeArr . map (( item , key ) => {
return < Route key = { key } exact path = { item . path } component = { dynamic ({ //保证路由的唯一性 exact key
app ,
model: item . models ,
component: item . component ,
}) } />
})
}
</ Switch >
</ Router >
</ Home >
</ ConnectedRouter >
);
}

export default RouterConfig ;

reducers : 其实 就是 对应reducer 同步改变 原state 只能在这里面改变state的状态值
和之前redux中的reducer是一样的
其实是省略了switch对于action.type的判断
以key的方式去对应不同方法对state的更新
reducers: {
save ( state , { payload }) { //action 的type 属性 对应的就是 方法名 {payload} 解构 action
return { ... state , ... payload }
}
},
也是接收了两个参数 原state 和一个action
effects : 异步操作 例如请求数据等, 其实就是简化了 saga 的使用
第一个参数是acion 第二个是 saga方法对象 里面可以结构出put call方法
effects: {
* fetchUser ( action , { call , put }) {
const { username , password } = action . values
const json = yield call ( fetchUser , 'http://localhost:8090/api/checkUser' , { //这个fetchUser 是引进来的方法 参数是对象的方式
method: 'POST' ,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded' , //设置请求头
htoken: localStorage . getItem ( 'htoken' ) || '' , //
hlogintime: localStorage . getItem ( 'hlogintime' ) || 0 ,
},
body: `busername= ${ username } &password= ${ password } `
})
if ( json . data . code ) {
localStorage . setItem ( 'htoken' , json . data . token )
localStorage . setItem ( 'hlogintime' , json . data . loginTime )
yield put ({ //派发 action 让reducers 接收 存储 在model 里面 type 属性不需要加 Login/ 在组件中如果你dispatch派发action 需要加Login/
type: 'save' ,
payload: json . data
})
}
return Promise . resolve ( json . data ) //返回 可以在dispatch后.hen 二次操作 比如跳转路由 还有从生命周期中 判断接收到的新参数如何进行跳转路由
}
},

subscriptions :在 dom ready后执行的

如何在组件中派发 及取到state
props上面就有dispatch的 因为 你已经dynamic 给她绑定了state
所有可以派发事件
this . props . dispatch ({
type: 'Login/fetchUser' , //值得注意的是 因为命名空间的不同,所有我们需要加上前缀
values
}). then (( res ) => { // .then的调用方式 是因为在effect中,最后我们返回了promise,这样我们就可以执行二次才做,例如跳转路由等
if ( res . code ) { // 我可以在fetchUser 后返回promise.resolve 然后 成功可以跳转路由
this . props . history . push ( '/Home/List' )
}
})

取到state值,还是老方法 mapStateToprops
通过connect()()
function mapStateToProps ( state ) {
return {
Login: state . Login
};
}

export default withRouter ( connect ( mapStateToProps )( WrappedNormalLoginForm ))
withRouter是用来练习routers的为props挂载router信息

example: 完整的model
import { fetchUser } from '../services/Login' // dva 给你封装好的 请求方式
// 这是一个登录的model 存储到了localStorage中
export default {
namespace: 'Login' , //命名空间
state: { //初始化state
id: 1 ,
},
reducers: {
//以key/value格式定义reducer,用于处理同步操作,唯一可以修改state的地方,由action触发
//格式为{state,action} => newState 或 [(state,action)=>newState,enhancer]
save ( state , { payload }) { //action 的type 属性 对应的就是 方法名 {payload} 解构 action
return { ... state , ... payload }
}
}, //https://www.jianshu.com/p/69f13e9123d9
effects: {
//用于处理异步操作和业务逻辑,不直接修改state,由action触发,可以触发actiob,可以与服务器交互,可以获取全局的state的数据等
//*(action,effects) => void 或 [*(action,effects) = >void,{type}]
//type类型 : takeEvery takeLatest trottle watcher
* fetchUser ( action , { call , put }) {
const { username , password } = action . values
const json = yield call ( fetchUser , 'http://localhost:8090/api/checkUser' , { //这个fetchUser 是引进来的方法 参数是对象的方式
method: 'POST' ,
headers: {
'Content-Type' : 'application/x-www-form-urlencoded' , //设置请求头
htoken: localStorage . getItem ( 'htoken' ) || '' , //
hlogintime: localStorage . getItem ( 'hlogintime' ) || 0 ,
},
body: `busername= ${ username } &password= ${ password } `
})
if ( json . data . code ) {
localStorage . setItem ( 'htoken' , json . data . token )
localStorage . setItem ( 'hlogintime' , json . data . loginTime )
yield put ({ //派发 action 让reducers 接收 存储 在model 里面 type 属性不需要加 Login/ 在组件中如果你dispatch派发action 需要加Login/
type: 'save' ,
payload: json . data
})
}
return Promise . resolve ( json . data ) //返回 可以在dispatch后.hen 二次操作 比如跳转路由 还有从生命周期中 判断接收到的新参数如何进行跳转路由
}
},
//定义subscription,subscription是订阅,用于订阅一个数据源,然后根据需要dispatch相应,action
//在app.start() 时被执行,数据源可以是当前的时间,服务器的websocket连接,keyboard输入,Geolocation变化,history路由变化等
//({dispatch,history},done) => unlisenFunction
//注意:如果要使用app.unmodel() subscription 必须返回unlisten方法,用来取消数据订阅
subscriptions: {},
};

Subscriptions 是一种从 源 获取数据的方法,它来自于 elm。

Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值