useDispatch 和 useSelector 在 antD pro 中的应用

592 阅读2分钟

跟着网上的教程做一个 todoList 的应用,采用 Ant Design Pro 的模板建立,但教程中是大概 2019 年,AntD pro 中组件默认是类型组件,但现有的模版会生成函数式组件,并且很多默认内容会在 app.tsx 中定义,比如 layouts 文件夹之类。可以参考官网升级到 V5 的文章:升级到 V5

于是就是自己探索怎么用 Hooks 来解决需要用到 react-redux 的地方。在 AntD 里面内置了 dva ,所以就用 dva 的方式在 models 里面创建配置,这个不需要考虑是类型还是函数型。用例可以参考官网的例子。我的配置如下:

export default {
    namespace: 'todo',
    
    state: {
        todoList:[]
    },

    effects: {
        *getTodoList(_, { call, put }) {
            const resData = yield call(getTodoList)
            console.log(resData);
            yield put({
                type: 'setTodoList',
                payload: resData
            })
        }
    },

    reducers: {
        setTodoList(state, {payload}) {
            return {
                ...state,
                todoList: payload
            }
        }
    }
}

然后在应用中如下使用两个 hooks,来达到函数组件与 redux 连接,也就是代替了原本类型组件所需要用到的 connect。

  const dispatch = useDispatch()
  let todoList = useSelector(state => state.todo.todoList)
    useEffect(() => {
    // const resData = todoList
    // setData(resData)
    dispatch({
      type: 'todo/getTodoList',
      payload: null
    })
  },[])
  
  ...
  
    const handleFinish = async (value) => {
    // const newData = await addTodoList(value)
    // setData(newData)
    addTodoList(value)
    dispatch({
      type: 'todo/getTodoList',
      payload: null
    })
    setIsModalVisible(false);
    value = ''
  }
  
  ...
  
  return (
    <PageHeaderWrapper>
      <ProTable
      columns={columns}
      rowKey="id"
      search={false}
      dateFormatter="string"
      dataSource={todoList} // 表格数据
      // request={async ()=>({data: await getTodoList()})}
      headerTitle="Todolist"
      toolBarRender={() => [
        <Button type="primary" key="primary" onClick={showModal}>
          <PlusOutlined />new todo
        </Button>,
      ]}
      />
      <Modal title="Create new todo" visible={isModalVisible} onOk={handleOk} onCancel={handleCancel} footer={null}>
          // handleFinish 提交表格
          <ProForm onFinish={value => handleFinish(value)}> 
            <ProFormText name="todo" label="Todo" rules={[{required:true}]}/>
          </ProForm>
      </Modal>
    </PageHeaderWrapper>
  )

其实一开始我想用自定义的 Hooks,毕竟在官网的 model 介绍里也在升级后成为了:

一种基于 hooks 范式的简易数据管理方案(部分场景可以取代 dva),通常用于中台项目的全局共享数据。

然后在自己的 models 文件封装 useGetTodo,然后因为 Protable 组件中的 request 组件自己封装了 useRequest 的 Hook,而 Hook 的规则中说到:

不要在循环,条件或嵌套函数中调用 Hook,确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们。

所以自定义 Hooks 不能嵌套在其他 Hooks 中。算是自己没遇到过的 bug,长个记性。不过不用 request 而用 dataSource ,在加上 useDispatch 和 useSelector 的使用,应该也可以解决全局共享状态的问题。之后可以再尝试一下。AntD Pro 还封装了 useModel 这个 API,也拥有消费 model 的能力,下次一定。

巩固了一下 Hooks 的规则和使用,菜就多练吧^^

源码:github.com/ShuchenEaso…