触发action 使用dispatch
让State改变需要reducer变化从而有新的store
dva好处在于不用想 redux一样还要维护一个常量
定义和用法
slice() 方法可从已有的数组中返回选定的元素。语法
arrayObject.slice(start,end)
参数 描述
start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。
routes/CounterPage.js
import React from 'react';
import Counter from '../components/Counter';
import { connect } from 'dva';
const CounterPage =({ counter ,dispatch }) => {
return (
<div>
<p>Counter</p>
<Counter counter ={ counter } dispatch= { dispatch } />//在组件内用只用传一次 在外层用要像这样多传一次
</div>
)
}
const mapStateToProps =(state) =>{
return
{ counter: state.counter };
};
export default connect (mapStateToProps)(CounterPage);
console.log()会在浏览器控制台打印出信息
console.dir()可以显示一个对象的所有属性和方法
同时还要修改components/Counter.js
import React from 'react';
const Counter =({ counter, dispatch}) => {
return (
<div>
<h1>{ counter.count } </h1>
<button onClick ={ ()=> {dispatch ({ type :'counter/add' }) } >
+
</button>
)
}
export default Counter;
models/counter.js
export default {
namespace:'counter',
state{
count:2
},
reducers:{
add(state,action){//由于type是add
return {
count:state.count + 1
};
},
}
}
处理异步动作
例:隔了几秒钟数值才发生变化
向服务器请求数据
yield put /call
https://www.cnblogs.com/handsomehan/p/7102346.html
component /counter.js
import React from 'react';
const Counter =({ counter, dispatch}) => {
return (
<div>
<h1>{ counter.count } </h1>
<button onClick ={ ()=> {dispatch ({ type :'counter/add' }) } >//必须要有命名空间
+
</button>
<button onClick ={ ()=> {dispatch ({ type :'counter/asyncAdd' }) } >
async +
</button>//异步动作
)
}
export default Counter;
在models/counter.js中
import { delay } from 'dva/saga';
export default {
namespace:'counter',
state{
count:2
},
reducers:{
add(state,action){//由于type是add
return {
count:state.count + 1
};
},
},
effects: {
//function* 省略成了*
*asyncAdd({ payload }, { call , put ,select }) {//select.namespace 取出这里的值
//select可以在saga中取到state的值
const counter = yield select (state => state.counter)
//或const counter = yeild select (({ counter }) => counter )
//或const counter = yeild select ( _ => _.counter )
//或const {counter} =yield select (_ => _);
yield call (delay,1000);//调用
yield put ({type: 'add' });//相当于dispatch
},
},
}
export default connect(({ products }) => ({ products, }))(Products); ```相当于
(state.products) => ({
products:products
})
若reducers和effects中出现同名的情况呢?
不停的循环
尽量避免重名
yield 回调 一步一步的执行
在src/index.js中
有很多model需要引用怎么办?
我们可以把它们放入一个文件然后在这里循环遍历出来
新建src/models/index.js
放入许多 app.model(require(’./models/namespace’).default);
再放入
涉及到的是require.context的知识点
const context = require.context('./',false,/\.js$/);
export default context
.keys()
.filter(item => item!== './index.js')
.map(key => context(key));
将src/index.js model那改为
require(’./models’).default.forEach(key=> app.model(key.default));
可选使用的redux-actions库
便于方便管理component里调用的dispatch
(github)
实现路由跳转的几种方式
1、常规
2、在组件里
components/counter.js
子组件:
const Counter =({history,...等其他要传的值}) => {
return (
<div>
<h1> {counter.count } </h1>
<button onClick={ () => history.push('/') }>返回首页</button>
</div>
)
}
在父组件 routes/CounterPage.js中
const CounterPage =( { history} ) =>{
return(
)
}
}
3、把组件包裹起来的方式’
引用
import { withRouter } from 'dva/router';
const Counter =....
export default withRouter(Counter);
4、link式
import { withRouter ,Link } from 'dva/router';
const Counter =....
{
<Link to='/'>home</Link>//链接式
}
export default withRouter(Counter);
5、上下文跳转context
component/Counter.js中
import ...
const Counter =( props, context)=>{
return (
<div>
<button onClick={ () => context.router.history.push('/') }>context go back</button>
</div>
)
}
static contextTypes ={
router:PropTypes.object
}
6、effects中进行跳转(使用了react-router-redux)
import {routerRedux }from 'dva/router'
const Counter =....
{
return (
<div>
<button onClick ={ () => dispatch (routerRedux.push('/'))}>routerRedux back</button>
</div>
)
}
7、在effects中进行跳转
components/counter.js
//将跳转加入到这里
models/counter.js
import { routerRedux } from 'dva/router';
import queryString from 'query-string';
effects: {
*....{
yield put (routerRedux.push('/'));//或
yield put (routerRedux.push ({
pathname: '/'
hash:'hello'//在地址后面加入#hello
search: queryString.stringify({
from:'rails' //地址后加?from=rail
})
})
}
}
订阅事件(监听变化 进行处理)
地址匹配另一种方式:利用正则表达式匹配
path-to-regexp(github
models/counter.js
export default {
namespace:...
subscriptions:{
setup( { dispatch,history}) { //setup 一个函数名字
window.onresize =() => {//窗口改变时
dispatch ( {type :'add'});
};
onClick({ dispatch }) {
document.addEventListener('click', () => {
dispatch ({type: 'add'});
})
}
},
setupHistory({dispatch ,history}) {
history.listen((location)=> {//location 得到地址路径名 如/counter
dispatch({type:'add'});//一进入就会执行add
})
}
},
...
}
const {dispatch} = props; //把props里的dispatch提取出来
onClick ={ () =>{...}} //里面是箭头函数
axios:
effects:{
*fetch(_,{ put ,call }) {//传入put call方法
yield put({ type:'fetch/start' });
try{//success
const user = yield call(axios.get,"url");
yield put({ type:"fetch/success",user:user});}
catch(e){//fail error
yield put({ tyoe:"FETCH_USER_SUCCEEDED",error:e.message});
}
},
},
reducers:{
'fetch/success'(state,action){
return {
isFetching:false,//是否正在加载
error:null,//是否有错
user:action.user//返回用户名
},
'fetch/error'(state,action){
return {
isFetching:false,
error:action.error,
user:null
}
}
},