Dva: model中state中的值改变后,如何更新组件?

Created on 27 Dec 2017  ·  14Comments  ·  Source: dvajs/dva

Form注册表单中,邮箱校验时,数据库中已经存在,返回code = 1, reducer中修改register model中的state:{code:1}, 触发组件更新,但无法在componentWillReceiveProps中午执行错误显示或者this.props.form.validateFields(['email'], { force: true }) 校验操作,否则导致死循环,这种场景如何处理?

Most helpful comment

@becky-guo 可以放在 routes 里请求,并不代表应该放在 routes 里,放 model 里处理的好处是你所有的行为可以集中管理,包括异步的和同步的。

All 14 comments

这个问题有人回答么,我也遇到了类似的问题,翻了好几个地方的文档,都没有解决问题。我在reducer中return了新的数据,route层在render里打印出了数据,但是是明显没有更新的

@Gaven-Xu 你在render中打印了就一定会更新,可以发代码。我的问题和你还不一样 不只是显示问题。我是想把服务端的返回码在form表单中以自定义错误提示的方式在某个field显示出来

窝在render里面打印的是没有更新的数据,很奇怪,不知道是不是漏写了什么,模仿官方demo写的,应该没有漏掉什么,@connect也写了

我的route:
`import React, { Component } from "react";
import { connect } from "dva";
import { Form, Icon, Input, Button, Row, Col, Table } from "antd";
import styles from "./AgentManage.less";

const FormItem = Form.Item;

@connect(state => ({
angetdata:state.angetdata
}))
export default class AgentManage extends Component {
state={
angetdata:[{
key: '1',
name: '胡',
age: 32,
address: '西湖'
}, {
key: '2',
name: '祖',
age: 42,
address: '西湖'
}]
}

componentDidMount() {
    // To disabled submit button at the beginning.
    // TODO: 暂时没用
    // this.props.form.validateFields();
    this.props.dispatch({
        type: "agent/fetch",
        payload:this.state
    });
}

shouldComponentUpdate= true;

render() {

    const columns = [{
        title: '姓名',
        dataIndex: 'name',
        key: 'name',
    }, {
        title: '年龄',
        dataIndex: 'age',
        key: 'age',
    }, {
        title: '住址',
        dataIndex: 'address',
        key: 'address',
    }];

    console.log(this.state)

    return (
        <div>
            <Row>
                <Col>
                    <Table dataSource={this.state.angetdata} columns={columns}/>
                </Col>
            </Row>
        </div>
    );
}

}
我的model: import { queryAgent } from "../services/agent";

export default {
namespace: "agent",

state: {
    angetdata: [],
    loading: false
},

effects: {
    *fetch({ payload }, { call, put }) {
        console.log("this m is from modal agent.js");
        yield put({
            type: "changeLoading",
            payload: true
        });
        // const response = yield call(queryAgent, payload);
        const response = [{
            key: '1',
            name: '胡彦斌',
            age: 32,
            address: '西湖区湖底公园1号'
        }, {
            key: '2',
            name: '胡彦祖',
            age: 42,
            address: '西湖区湖底公园1号'
        }];
        yield put({
            type: "returnAgentData",
            payload: Array.isArray(response) ? response : [],
        });
        yield put({
            type: "changeLoading",
            payload: false
        });
    }
},

reducers: {
    returnAgentData(state, action) {
        // console.log('state',state,'action',action)
        console.log('reducers已经执行:'+typeof action.payload, action.payload)
        return {
            ...state,
            angetdata: action.payload
        };
    },
    changeLoading(state, action) {
        return {
            ...state,
            loading: action.payload
        };
    },
},

};
`

@Gaven-Xu render 中取值的时候不要直接this.state, 试试 const {agent:{angetdata}} = this.props

我试过,我的state下直接是angetdata,所以应该是const {angetdata} = this.props吧,我打印了props,angetdata字段是有的,但是值为undefined

@becky-guo 你的问题我考虑可以这么解决,其实你这是一个表单异步校验的需求。ant-design官方对于异步校验好像并没有给出实践。但是可以利用 ant-design 自定义校验的机制自己进行异步校验,代码如下:

import request from 'path-to-dva-request';
asyncCheck = (rule, value, callback) => {
    request('path/to/valid/email', {
        method: 'post',
        body: emialValue
    }).then(({data})=> {
        if(data.code == 1) {
           callback('邮箱已经存在');
       }else {
           callback();
       }
   })
}

在 ant-design 的 自定义校验中,如果 callback 方法不调用,验证会一直处于阻塞状态。这种异步验证表单的问题不需要通过 redux store 来托管数据,这样反而会丢失数据获取到的时间,导致需要在 componentWillReceiveProps 中去通过其他 ‘脏’ 手段触发表单验证。

@yvanwangl 是的 我纠结的也就是如何很好的利用model托管,真正的做到视图与数据分离。

@yvanwangl 感谢提供的思路,不然掉坑里了 哈哈

@becky-guo 客气,问题解决了就把它关了吧 : )

@yvanwangl @sorrycc 服务端接口返回的数据格式{code:0,msg:"xxxx"} ,在model effect处理不同code的情况,给页面相应的提示是频繁的操作, 如果这个没法处理,全部在页面写request,那model是不是没有意义了,朋友们给点建议

@becky-guo 我个人感觉,dva model 的作用是对 redux reducer 的一种切片处理,方便你不同领域模型的数据分开,就你上面的那个需求而言是一个数据的临时验证逻辑,并不需要redux store去维护你的状态,因为你输入不同的邮箱可能会返回不同的 code,是一种‘瞬时’性的数据,所以不用 redux store 去存储。
model 是 dva 的核心, 你可以认为是一个调度器,model 中的 state 是 redux reducer 的 initialState, effects 会调度给 saga 处理,reducers 会直接调度给 redux 处理,同时还给了一个 subscriptions 钩子注册功能,让你可以监听例如路由这样的事件,model 存在的意义并不是 '持久' 数据的,这个是底层 redux 的作用。以上仅代表个人理解。

@yvanwangl 悟了!我之前执着于一定要把api请求放在model里,其实可以在routes里请求,做状态判断,然后再把需要更新的结果dispatch到model中,通过reducer去更新这样就完美了。就是把你说的”瞬时“数据和”持久“数据在view分隔开来处理。感谢!

@becky-guo 可以放在 routes 里请求,并不代表应该放在 routes 里,放 model 里处理的好处是你所有的行为可以集中管理,包括异步的和同步的。

Was this page helpful?
0 / 5 - 0 ratings