dva——03——models异步处理

本文介绍了在React应用中使用Dva.js进行状态管理和异步数据处理的方法。通过connect高阶组件,组件能够获取并响应状态变化。在model中,利用effects进行异步操作,如数据请求,然后通过reducers更新状态。同时,展示了如何进行数据缓存,以及如何通过subscriptions进行初始化设置,如加载指示器的显示和隐藏。此外,还讨论了如何处理跨域请求,利用webpack的proxy配置进行反向代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述访问时根据路由动态决定加载哪些组件,如果组件加上connect,可以获得状态(model),组件dispatch一个action到模型中,如果是同步则到Reducer,状态发生改变,谁用了connect就得到这个状态
如果是异步到effect,需要写成生成器的写法,在effect中先进行异步处理,处理完了再通过同步给到Reducer,Reducer是负责数据更新的,再通过connect传给组件。Subscription做一些初始化设置,比如loadding框显示转圈,数据请求完后隐藏转圈

subscription的使用:history(路由地址) 进行各种初始化设置
在这里插入图片描述在这里插入图片描述

异步操作例子
需求是:Cinema组件做数据缓存,如果是第一次进入页面,走Ajax请求异步请求数据,后面再次进入该页面直接走缓存

先用connect高阶函数包裹Cinema组件,这样Cinema组件才能拿到状态,在Cinema组件中发起diapatch,model里的effects里的函数接收到
在model异步函数effects中请求数据,yield call一个函数,这个函数是service里的,service请求数据,model拿到之后再put给reducers,再传给页面
代码展示:
要打开入口文件index.js的model
在这里插入图片描述Cinema.js

import { connect } from "dva";
import React, { Component } from "react";

class Cinema extends Component {
  componentDidMount() {
    if (this.props.list.length === 0) {
      // dispatch一个action,action解构赋值的结果是type和payload,这里只有type
      this.props.dispatch({
        type: "maizuo/getCinemaList",
      });
    } else {
      console.log("缓存",this.props.list);
    }
  }
  render() {
    return (
      <div>
        <ul>
          {this.props.list.map((item) => (
            <li key={item.cinemaId}>{item.name}</li>
          ))}
        </ul>
      </div>
    );
  }
}
// 可以将mapStateToProps函数写外面,也可以直接写在connect里面
const mapStateToProps = (state) => {
  // console.log(state,333355);
  // 将对象名为list数据传给Cinema组件,组件的props能接收到名为list的数据
  return { list: state.maizuo.list };
};
// 如果要简写省去return,不能要{}包裹,会被当成函数体而不是对象,所以要在外面用()包起来表示一个整体的东西
// 错误写法
// const mapStateToProps = (state) => 
//    { list: state.maizuo.list}
// 正确写法
//  const mapStateToProps = (state) => ({list: state.maizuo.list})
export default connect(mapStateToProps)(Cinema);

models/maizuo.js

import {getCinemaListService} from "../services/maizuo"
export default {
  namespace: "maizuo",
  state: {
    isShow: true,
    list: [],
  },
  subscriptions: {
    setup({ dispatch, history }) {
      console.log("初始化");
    },
  },
  reducers: {
    hide(prevState, action) {
      // 这里合并而不直接更改数据是因为prevState是不可变的,保证状态不可变
      // 所以我们要深复制一遍,再return出去(同名的直接覆盖)
      return { ...prevState, isShow: false };
    },
    show(prevState, action) {
      return { ...prevState, isShow: true };
    },
    changeCinemaList(prevState,{type,payload}){
      // 把payload数据放到命名为list的里去
         return{...prevState,list:payload}
    }
  },
  effects: {
    // 第一个参数是action可以解构赋值成type和payload
    *getCinemaList(action, { call, put }) {
      // call进行异步取数据,put发送新的action到reducers中
      var res = yield call(getCinemaListService);
      console.log(res);
      //  put参数也是action对象,解构赋值为type和payload
      yield put({
        type: "changeCinemaList",
        payload: res.data.data.cinemas,
      });
    },
  },
};

services/maizuo.js

import request from "../utils/request";
export function getCinemaListService() {
  return request(
    "https://m.maizuo.com/gateway?cityId=330100&ticketFlag=1&k=4103390",
    {
      headers: {
        "X-Client-Info":'{"a":"3000","ch":"1002","v":"5.2.0","e":"16460383564094280654127105","bc":"330100"}',
        "X-Host": "mall.film-ticket.cinema.list",
      },
    }
  );
}

如果请求的网站有跨域怎么办,比如我们之前请求的网站是卖座网无跨域限制,现在我们在center页面中请求猫眼网(有跨域)的数据,在.webpackrc文件(支持dev-server、反向代理)中配置反向代理,这个文件必须是json格式,所以changeOrigin得加双引号,将changeOrigin(改变源)设置为true,将这个文件改成json
在这里插入图片描述在这里插入图片描述在猫眼网控制台的网络找到请求网址
在这里插入图片描述

在这里插入图片描述将开头剪切到反向代理中
在这里插入图片描述
在这里插入图片描述一朝/ajax进行请求时,反向代理转发到target地址,由服务端发请求,它们无跨域限制

请求另一个地址例子:
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
第二个例子的代码:
.webpackrc

{
  "proxy": {
    "/api": {
      "target": "https://i.maoyan.com",
      "changeOrigin": true
    }
  }
}

Center.js

import React, { Component } from "react";
import { withRouter } from "dva/router";
import request from "../utils/request"
export default class Center extends Component {
  componentDidMount(){
    request(
      "/api/mmdb/movie/v3/list/hot.json?ct=%E6%9D%AD%E5%B7%9E&ci=50&channelId=4"
    ).then((res) => {
      console.log(res.data);
    });
  }
  render() {
    return (
      <div>
        Center
        {/* <Child props={this.props} /> */}
        {/* 不传props的情况下可以使用withRouter */}
        <WithChild />
      </div>
    );
  }
}
class Child extends Component {
  render() {
    return (
      <div>
        <button
          onClick={() => {
            // console.log(this.props)
            localStorage.removeItem("token");
            this.props.history.push("/login");
          }}
        >
          退出登录
        </button>
      </div>
    );
  }
}
// 组件首字母要大写,注意
const WithChild = withRouter(Child);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值