bai3/note

Reducer和Effect

Opened this issue · 0 comments

bai3 commented

Reducer

reducer 是一个函数,接受state和action,返回老的或者新的state。即:(state,action) => state

增删改

以todo为例

app.model({
    namespace: 'todos',
    state: [],
    reducers: {
        add(state, { payload: todo}) {
            return state.concat(todo);
        },
        remove(state, { payload: id }){
            return state.filter(todo => todo.id !== id);
        },
        update(state, { payload: updatedTodo}){
            return state.map(todo => {
                if(todo.id === updatedTodo.id) {
                    return {...todo,...updatedTodo};
                }else{
                    return todo;
                }
            })
        }
    }
})

嵌套数据的增删改

建议最多一层嵌套,以保持state的扁平化,深层嵌套会让reducer很难写和难以维护。

app.model({
    namespace: 'app',
    state: {
        todos: [],
        loading: false
    },
    reducer: {
        add(state, { payload:todo }) {
            const todos = state.todos.concat(todo);
            return { ...state,todo};
        }
    }
})

Effect

示例:

app.model({
    namespace: 'todos',
    effect: {
        *addRemote({ payload: todo}, {put, call}){
            yield call(adddTodo, todo);
            yield put({ type:'add', payload: todo})
        }
    }
})

Effects

  • put

    用户触发action

    yield put({ type: 'todos/add', payload: 'Learn Dva'}
  • call

    用于调用异步逻辑,支持promise

    const result = yield call(fetch, '/todos')
  • select、

    用于从state里获取数据

    const todos = yield select(state => state.todos);

错误处理

全局错误处理

dva里,effects和subsciptions的抛错全部会走onError hook,所以可以在onError里统一处理错误

const app = dva({
    onError(e,dispatch) {
        console.log(e.message)
    }
})

在effects里的抛错和reject的promise就都会被捕获到了

本地错误处理

如果需要对某些effects的错误进行特殊处理,需要再effect内部加try catch。

app.model({
    effects: {
        *addRemote(){
            try{

            }catch(e){
                console.log(e.message)
            }
        }
    }
})

异步请求

GET和POST

import { request } from "../util/request";

//GET
request('/api/todos')

//POST
request('/api/todos',{
    method: 'POST',
    body: JSON.stringify({a:1})
})

统一错误处理

假如约定后台返回以下格式时,做统一的错误处理

{
    status: 'error',
    message: ''
}

编辑 utils/request.js 加入以下中间件:

function parseErrorMessage({data}){
    const {status, message} = data;
    if(status === 'error'){
        throw new Error(message)
    }
    return { data }
}

然后,这类错误就会走到onError hook里