dva 基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,今天就讲一下具体的使用
实现的效果:计算器的同步增减及异步修改数据
1.创建ui component
return ( <> <div> 测试组件 Option:<input ref={inputRef} defaultValue={0} /> <br/> <div>变量:{count || 0}</div> <button onClick={handleAdd}>同步+</button> <button onClick={handleReduce}>同步-</button> <button onClick={handleAsync}>异步+</button> <hr/> </div> </> )
2.创建model(5个api)
const TestModel={ namespace:"testModel", // 命名空间,model数据做隔离 state:{ // 变量存储,尽量扁平化处理,不要嵌套层级多 count:1, }, reducers:{ // 同redux中的reducer模块,以key/value定义reducer。用于处理同步操作,唯一可以修改 state 的地方。由 action 触发 add(state, { payload}) { const count = state.count + payload return {...state,count:count} }, reduce(state,{payload}) { const count = state.count - payload return {...state,count:count} }, }, effects:{ // 以 key/value 格式定义 effect。处理异步操作,不直接修改 state。由 action 触发,可以触发 action,可以和服务器交互... *changeAsync(_, {call,put}) { yield call(delay,500) yield put({type:'add',payload:2}) } },
// 以 key/value 格式定义 subscription。subscription 是订阅,用于订阅一个数据源,然后根据需要 dispatch 相应的 action。在 app.start() 时被执行,数据源 可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。 subscriptions: { setup({ dispatch, history }, done) { return history.listen((location) => { if ( location.pathname === 'xxx' ) { dispatch({type:'XXX',payload:XXX}) } }); }, },
}
3.connect连接:引入connect模块
import {connect} from 'dva' export default connect(({testModel})=>( { count:testModel.count, } ))(Index)
4.组件内部使用
① 获取dva存储的变量:组件自带dispact方法和转换后的变量
const Index= (dispatch,state1,state2...)=>{
}
② 组件内部修改数据通过dispatch方法
dispatch({
type:[namespace]/同步reducer或异步的effects名,
payload:传入的参数
})
5.完整代码
test.js
import React,{useRef,useState,useEffect} from 'react' import {connect} from 'dva' const ChildComp = (props) =>{ const {userName,userAge} = props return <> <p>ChildComp子页面获取数据</p> <div>子页面获取到的姓名:{userName}</div> <div>子页面获取的年龄:{userAge}</div> </> } const Index=({dispatch,count,userName,userAge})=> { const inputRef = useRef() useEffect(()=>{ // console.log('count数据变化了') return () =>{ } },[count]) const handleAdd = () =>{ dispatch({type:'testModel/add',payload:Number(inputRef.current.value)}) } const handleReduce = ()=>{ dispatch({ type:'testModel/reduce', payload:Number(inputRef.current.value) }) } const handleAsync = ()=>{ dispatch({type:'testModel/changeAsync',payload:Number(inputRef.current.value)}) } return ( <> <div> 测试组件 Option:<input ref={inputRef} defaultValue={0} /> <br/> <div>变量:{count || 0}</div> <button onClick={handleAdd}>同步+</button> <button onClick={handleReduce}>同步-</button> <button onClick={handleAsync}>异步+</button> <hr/> </div> </> ) } // const mapStateToProps= (state) =>{ // return { // count:state.testModel.count, // userName:state.testModel.userName, // userAge: state.testModel.userAge // } // } export default connect(({testModel})=>( { count:testModel.count, userName:testModel.userName, userAge:testModel.userAge } ))(Index)
model
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout)); const TestModel={ namespace:"testModel", state:{ count:1, userName:'wang' }, reducers:{ add(state, { payload}) { const count = state.count + payload return {...state,count:count} }, reduce(state,{payload}) { const count = state.count - payload return {...state,count:count} }, changeUserName(state,{payload}) { return {...state,...payload} } }, effects:{ *changeAsync(_, {call,put}) { yield call(delay,500) yield put({type:'add',payload:2}) } } } export default TestModel
界面效果:
return ( <> <div> 测试组件 Option:<input ref={inputRef} defaultValue={0} /> <br/> <div>变量:{count || 0}</div> <button onClick={handleAdd}>同步+</button> <button onClick={handleReduce}>同步-</button> <button onClick={handleAsync}>异步+</button> <hr/> </div> </> )subscriptions: { setup({ dispatch, history }, done) { return history.listen((location) => { if ( location.pathname === '/app/admin/weak/vuln' || location.pathname === '/app/admin/weak/vuln/hostadd' || location.pathname.indexOf('/app/admin/weak/vuln/host/') !== -1 ) { dispatch({ type: 'init', payload: { vulnInstanceType: 'serviceManage', }, }); } if ( location.pathname === '/app/admin/weak/vuln/website' || location.pathname === '/app/admin/weak/vuln/websiteadd' || location.pathname.indexOf('/app/admin/weak/vuln/website') !== -1 ) { dispatch({ type: 'init', payload: { vulnInstanceType: 'webserviceManage', }, }); } }); }, },