使用 umi + dva 搭建 react 项目

起步

首先通过 umi 快速创建项目

mkdir myapp && cd myapp
yarn create @umijs/umi-app
yarn

启动项目

yarn start

路由

  1. 通过配置文件配置路由
    直接在.umirc.ts 的 routes 中配置路由
export default {
  routes: [
    { exact: true, path: '/', component: 'index' },
    { exact: true, path: '/user', component: 'user' },
  ],
}
  1. 如果 .umirc.ts 里没有 routes 那么文件系统即路由,通过目录和文件及其命名分析出路由配置

  2. 动态路由
    约定 [] 包裹的文件或文件夹为动态路由。

比如上面的目录最后会被动态编译成 /test/:id 路由,所以我们通过 props.match.params 拿到的就是 id

  1. 动态可选路由
    约定 [ $] 包裹的文件或文件夹为动态可选路由

比如:

src/pages/users/[id$].tsx 会成为 /users/:id?
src/pages/users/[id$]/settings.tsx 会成为 /users/:id?/settings

这样就算直接访问/test 或者 访问/test/:id都不会报错

安装 dva

yarn add dva

这里需要注意每个目录下面必须有一个service和model文件,具体代码见
https://github.com/wanglifa/umi-dva-react/tree/9a3a403a8d35e242ef77e04d068d3f3428a9dbff

reducer 和 effect 的用法

dva里想要修改 modal 里的 state,只能通过 reducer 来修改,如果是同步的直接通过 dispatch 触发 reducer,如果需要异步修改那么我们就在effect里,成功后调用 reducer
1). 通过 effect 调用接口成功后修改 state

export default {
  namespace: 'users',
  state: {
    list: [],
    total: null,
  },
  reducers: {
    modifyList(state, { payload }) {
      return {...state, ...payload}
    },
  },
  effects: {
    *_getList({payload, callback}, { call, put }) {
      const response = yield call(getList, { payload });
      console.log(response)
      if (response.code === 200) {
        if (callback && typeof callback === 'function') {
          callback(response); // 返回结果
          // 调用接口成功后修改 state
          yield put({
            type: 'modifyList',
            payload: {list: response.data}
          })
        }
      }
    },
  },
};

使用 dispatch 触发

useEffect(() => {
    dispatch({
      type: 'users/save',
      payload: {
        data: [{name: 'lifa'}],
        total: 2
      },
      callback: (res: any) => {
        console.log(res)
      },
    })
  }, [])

2). 直接通过 reducer 修改 state

import React, {memo} from 'react;
import { connect } from 'dva';
const Test = (props) => {
  const { users } = props;
  const handleModifyList = () => {
  dispatch({
    type: 'users/modifyList',
     payload: {
    // 修改 state 里的 list 的值
       list: [{a: 1}]
     }
  })
}
return (
  <>
    
{users.list[0]}
) } export default connect(({users}) => ({users}))(memo(Test))

何时使用 state

1). 对于没有父子关系的组件
2). 层级很深的父子组件,一个属性传了超过两次的时候
如何使用
1). 引入 connect
2). connect 的第一个参数为我们需要拿到 state 的 modal 的namespace

connect(({users}) => ({users}))

3). 通过 props.modal里的namespace获取对应的state

props.users.list

使用useSelector useDispatch 替代connect

  • seSelector()
const result : any = useSelector(selector : Function, equalityFn? : Function)

主要作用:
从redux的store对象中提取数据(state)。

注意:选择器函数应该是纯函数,因为它可能在任意时间点多次执行。

import React from 'react'
import { useSelector } from 'react-redux'

export const CounterComponent = () => {
  const counter = useSelector(state => state.counter)
  return 
{counter}
}
  • useDispatch()
const dispatch = useDispatch()

返回Redux store中对dispatch函数的引用。你可以根据需要使用它。

import React from 'react'
import { useDispatch } from 'react-redux'

export const CounterComponent = ({ value }) => {
  const dispatch = useDispatch()

  return (
    
{value}
) }

将dispatch传递给子组件时,建议使用useCallback来进行回调,否则,由于更改了引用,子组件可能会多次 render。

  • useStore()
const store = useStore()

这个Hook返回redux 组件的store对象的引用。

这个钩子应该不长被使用。useSelector应该作为你的首选。但是,有时候也很有用。来看个例子:

import React from 'react'
import { useStore } from 'react-redux'

export const CounterComponent = ({ value }) => {
  const store = useStore()

  // 仅仅是个例子! 不要在你的应用中这样做.
  // 如果store中的state改变,这个将不会自动更新
  return 
{store.getState()}
}

dva 中使用

原始写法

  • model.js
export default {
  namespace: 'user',
  state: {
    userInfo:null,
  },
  effects: {
      *fetchUser({paylaod},{call,put}){
          const res = yield(api,payload)
          yield put({
            type: 'save',
            payload: {
                userInfo:res   
            },
          });
      }
  },
  reducers:{
      save(state, { payload }) {
        return {
            ...state,
            ...payload,
        };
      },
  }
}

在页面中使用

import {connect} from 'dva'

const Home = props=>{
    // 获取数据
    const {user,loading,dispatch} = props
    
    // 发起请求
    useEffect(()=>{
        dispatch({
            type:'user/fetchUser',payload:{}
        })
    },[])
    
    // 渲染页面
    if(loading) return 
loading...
return (
{user.name}
) } export default connect(({loading,user})=>({ loading:loading.effects['user/fetchUser'], user:user.userInfo }))(Home)

使用 useDispatch useSelector 优化上面的代码

import {useDispatch,useSelector} from 'dva'

const Home = props=>{
    
    const dispatch = useDispatch()
    
    const loadingEffect = useSelector(state =>state.loading);
    const loading = loadingEffect.effects['user/fetchUser'];
    const user = useSelector(state=>state.user.userInfo)
    
    // 发起请求
    useEffect(()=>{
        dispatch({
            type:'user/fetchUser',payload:{}
        })
    },[])
    
    // 渲染页面
    if(loading) return 
loading...
return (
{user.name}
) } export default Home

你可能感兴趣的:(使用 umi + dva 搭建 react 项目)