内容简介:在本文中,我想向大家介绍如果你还不知道在日常的开发中,我们常常会碰到一些列表页的开发需求。
在本文中,我想向大家介绍 React Hooks
在列表页中的实践,主要是通过 useReducer
和 useEffect
来实现的。以及表达一下我对 React Hooks
的理解与思考。
如果你还不知道 React
的这个新特性 React Hooks
,那么点击Hooks 简介 ; 如果你想看直接查看最后的实现效果,请点击 仓库
。
使用场景
在日常的开发中,我们常常会碰到一些列表页的开发需求。
一个列表页的最基本的功能就是列表的展示,而列表的展示就需要很多 state
去管理,比如:列表数据、数据总数、当前页、展示条数等等。而这些 state
绝大部分是所有列表页的都通用的即有共同的逻辑。
在以往的方案中还没有特别好的方案,可以共用这些逻辑代码。高阶组件 HOC
可以,但会引入组件层级过深的问题。(如读者有兴趣,可自行去了解高阶组件的用途,本文不深入讨论)。
好消息是, React Hooks
就能帮助我们完成这个心愿。
做什么
我们要是现实一个自定义 Hook useTable
,简单说明一下功能
-
接收一个
url
,向外暴露{ onSearch, bind: { loading, dataSource, pagination: { current, pageSize, total }, onChange } }
。 这个是基于antd
开发的,所以bind
内的东西是绑定在antd
的Table
组件上的。 - 在页面初始化时,自动请求数据
- 在页面卸载时,取消异步请求的后续操作
-
onChange
和onSearch
时自动请求数据 - 在 loading 中,不会触发新的异步请求
好了话不多说,直接上代码。
// useTable.js import { useReducer, useEffect } from 'react'; import axios from 'axios'; // action type const DATA_CHANGE = 'DATA_CHANGE'; const STATE_CHANGE = 'STATE_CHANGE'; const DEFAULT_STATE = { loading: false, current: 1, pageSize: 10, total: 0, order: false, field: '', dataSource: [], params: {}, } // 用作 useReducer 中的 reducer const reducer = (state, action) => { const { type, data: { dataSource, ...nextState } } = action; switch (type) { case STATE_CHANGE: return {...state, ...nextState}; case DATA_CHANGE: return {...state, dataSource, ...nextState}; default: return state; } } export default (url, initState = {}) => { /** * useReducer 的概念和 redux 很像 * 会返回一个 dispatch 函数,调用的时候传给它一个 action * 相应的会有一个 reducer 函数,用于数据处理 */ const [{ loading, // 加载态 current, // 当前页 pageSize, // 一页多少条 total, // 总共多少条 order, // 排序方向 field, // 排序字段 dataSource, // 数据 params, // 额外搜索项 }, dispatch] = useReducer(reducer, { ...DEFAULT_STATE, ...initState, }); // 获取数据的 hooks useEffect(() => { let cancel = false; dispatch({ type: STATE_CHANGE, data: { loading: true } }); axios.post( url, { current, pageSize, order, field, ...params }, ).then(({ data, status }) => { if (status === 200) return data; }).then(({ data = [], total }) => { !cancel && dispatch({ type: DATA_CHANGE, data: { dataSource: data, total }}); }).finally(() => dispatch({ type: STATE_CHANGE, data: { loading: false } })); // 返回值时页面卸载之后调用的函数 return () => cancel = true; }, [url, current, pageSize, order, field, params]); // 当这几个状态改变时自动调用函数 // 搜索事件 function onSearch(nextParams) { // 点击搜索按钮 跳到第一页 !loading && dispatch({ type: STATE_CHANGE, data: { params: nextParams, current: 1 } }); } // 变更事件 function onChange({ current, pageSize }, filters, { order = false, field = ''}) { !loading && dispatch({ type: STATE_CHANGE, data: { current, pageSize, order, field }}); } return { onSearch, bind: { loading, dataSource, pagination: { current, pageSize, total }, onChange, } }; } // UseHooksTable.js import React, { Fragment } from 'react'; import { Table } from 'antd'; import SearchForm from './SearchForm'; import useTable from './useTable'; const url = 'https://www.easy-mock.com/mock/5cf8ead34758621a19eef994/getData'; function UseHooksTable () { // 使用自定义 hook const { onSearch, bind } = useTable(url); const columns = [ { title: '编号', dataIndex: 'id' }, { title: '姓名', dataIndex: 'name' }, { title: '年龄', dataIndex: 'age' }, { title: '邮箱', dataIndex: 'email' }, { title: '主页', dataIndex: 'url' }, { title: '城市', dataIndex: 'city' }, ]; return ( <Fragment> <SearchForm onSearch={onSearch}/> <Table rowKey={'id'} columns={columns} {...bind} /> </Fragment> ); } export default UseHooksTable; 复制代码
在代码中的注释简单解释了一下代码,应该也没有什么难点。
解决了什么问题
到此为止,我们应该思考 React Hooks
可以给我们带来些什么。
为此,我额外的写了一个使用 class
方式实现的列表页,下面上代码
import React, { Component, Fragment } from 'react'; import { Table } from 'antd'; import axios from 'axios'; import SearchForm from './SearchForm'; const url = 'https://www.easy-mock.com/mock/5cf8ead34758621a19eef994/getData'; class UseClassTable extends Component { state = { loading: false, current: 1, pageSize: 10, total: 0, order: 0, field: '', params: { name: '', }, dataSource: [], } cancel = false; columns = [ { title: '编号', dataIndex: 'id', sorter: true }, { title: '姓名', dataIndex: 'name', sorter: true }, { title: '年龄', dataIndex: 'age', sorter: true }, { title: '邮箱', dataIndex: 'email', sorter: true }, { title: '主页', dataIndex: 'url', sorter: true }, { title: '城市', dataIndex: 'city', sorter: true }, ]; componentDidMount() { this.getData(); } componentWillUnmount() { this.cancel = true; } // 搜索事件 handleSearch = (nextParams) => { // 点击搜索按钮 跳到第一页 !this.state.loading && this.setState({ params: nextParams, current: 1 }, this.getData); } // 变更事件 handleTableChange = ({ current, pageSize }, filters, { order = false, field = ''}) => { !this.state.loading && this.setState({ current, pageSize, order, field }, this.getData); } getData() { const { current, pageSize, order, field, params } = this.state; this.setState({ loading: true }, () => { axios.post( url, { current, pageSize, order, field, ...params }, ).then(({ data, status }) => { if (status === 200) return data; }).then(({ data = [], total }) => { !this.cancel && this.setState({ dataSource: data, total }); }).finally(() => this.setState({ loading: false })); }); } render() { const { loading, // 加载态 current, // 当前页 pageSize, // 一页多少条 total, // 总共多少条 dataSource, // 数据 } = this.state; return ( <Fragment> <SearchForm onSearch={this.handleSearch}/> <Table rowKey={'id'} loading={loading} columns={this.columns} pagination={{ current, pageSize, total }} dataSource={dataSource} onChange={this.handleTableChange} /> </Fragment> ) } } export default UseClassTable; 复制代码
我们可以看到使用 Hooks
的方式,我们可以把共有的逻辑封装到 Hooks
中,在所有有共有逻辑的页面都使用这样的 hook
,代码行数可以从原先的80行减少到30行,代码变得简单易懂,使用起来也很简单,提高的代码的复用性。
这应该就是 Hooks
的魅力。
结语
我们可以想象到,以后的社区会提供给我们有趣的 Hooks
。
在我们自己的开发中,也可以使用 Hooks
来封装我们的共有逻辑,效率可以大大提高。
而且最重要的是, Hooks
可以让我们的 代码变得美观
。
嗯,这很重要,哈哈哈哈哈哈。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 独家|React Native 无限列表的优化与实践
- C#列表到列表转换
- Python笔记(二):列表+列表数据处理+函数
- python创建列表和向列表添加元素方法
- 在Bootstrap开发框架中使用bootstrapTable表格插件和jstree树形列表插件时候,对树列表条件和查询...
- Python 列表(List)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
程序员2010精华本
程序员杂志社 / 电子工业 / 2011-1 / 49.00元
《程序员(2010精华本)》主要内容:《程序员》创刊10年来,每年末编辑部精心打造的“合订本”已经形成一个品牌,得到广大读者的认可和喜爱。今年,《程序员》杂志内容再次进行了优化整合,除了每期推出的一个大型专题策划,各版块也纷纷以专题、策划的形式,将每月的重点进行了整合,让内容非常具有凝聚力,如专题篇、人物篇、实践篇等。另外杂志的版式、色彩方面也有了很大的飞跃,给读者带来耳目一新的阅读体验。一起来看看 《程序员2010精华本》 这本书的介绍吧!