记录一次完整的react hooks实践


Posted in Javascript onMarch 11, 2019

写在前面

记录一次完整的react hooks实践

React在16.8版本正式发布了Hooks。关注了很久,最近正好有一个小需求,赶紧来试一下。

需求描述

需求很简单,部门内部的一个数据查询小工具。大致长成下面这样:

记录一次完整的react hooks实践

用户首次访问页面,会拉取数据展示。输入筛选条件,点击查询后,会再次拉取数据在前端展示。

需求实现

使用React Class Component的写法

如果使用以前的class写法,简单写一下,代码可能大概长成下面这样:

import React from 'react';
import { Tabs, Input, RangeTime, Button, Table } from './components';

class App extends React.Component {
  ...
  state = {
    type: [],
    id: '',
    title: '',
    date: [],
    dataList: []
  }
  componentDidMount() {
    this.fetchData();
  }
  render() {
    <Tabs value={this.state.type} onChange={this.handleTypeChange}/>
    <Input value={this.state.id} label="ID" onChange={this.handleIdChange}/>
    <Input value={this.state.id} label="标题" onChange={this.handleTitleChange}/>
    <RangeTime value={this.state.date} onChange={this.handleRangeTimeChange}/>
    <Button onClick={this.handleQueryBtnClick}>查询</Button>
    <Table dataList={this.state.dataList} />
  }
  
  fetchData() {
    ...
    this.setState({
      dataList
    });
  }

  handleTypeChange() {
    ...
    this.setState({
      type,
    });
  }
  
  handleIdChange() {
    ...
    this.setState({
      id,
    });
  }

  handleTitleChange() {
    ...
    this.setState({
      title,
    });
  }

  handleRangeTimeChange() {
    ...
    this.setState({
      date,
    });
  }

  handleQueryBtnClick() {
    ...
  }
  ...
}

使用React Hooks的写法

关于React hooks的相关内容,这里就不赘述了。可以直接查看react官方文档,写得非常好。

https://reactjs.org/docs/hooks-intro.html

本次需求其实就两个逻辑:1、输入筛选项 。2、查询数据

主页面一个hooks,处理筛选项以及数据展示。数据请求逻辑单独弄一个hooks。

主页面hooks:

import React, { useState, useEffect} from 'react';
import { Tabs, Input, RangeTime, Button, Table } from './components';

const App = () => {
  // 数据类型
  const tabs = [{ key: 1, value: '类型1' }, { key: 0, value: '类型2' }];
  const [tab, setTab] = useState(1);
  // 数据ID
  const [dataId, setDataid] = useState('');
  // 标题
  const [title, setTitle] = useState('');
  // 时间区间, 默认为至今一周时间
  const now = Date.now();
  const [timeRange, setTimeRange] = useState([now - 1000 * 60 * 60 * 24 * 7, now]);
  // 数据列表
  const [dataList, setDataList] = useState([]);

  // 点击搜索按钮
  function handleBtnClick() {
    // 请求数据
    ...
  }

  return <section className="app">
    <Title title="数据查询" />
    <Tabs label="类型" tabs={tabs} tab={tab} onChange={setTab} />
    <Input value={dataId} placeholder="请输入数据ID" onChange={setDataid}>ID</Input>
    <Input value={title} placeholder="请输入数据标题" onChange={setTitle}>标题</Input>
    <TimeRange label="数据时间" value={timeRange} onChange={handleTimeChange}/>
    <article className="btn-container">
      <Button type="primary" onClick={handleBtnClick}>
        查询          
      </Button>
    </article>
    <Table dataList={dataList}></Table>
  </section>
};

上面的代码,完成了筛选项的处理逻辑。下面来实现负责数据请求的hooks.

数据请求hooks:

import React, { useState, useEffect } from 'react';
import jsonp from '../tools/jsonp';


function MyFecth(url) {
  // 是否正在请求中
  const [isLoading, setIsLoanding] = useState(false);
  // 请求参数
  const [queryParams, setQueryParams] = useState(null);
  // 请求结果
  const [data, setData] = useState(null);

  // 向接口发起请求
  const fetchData = async () => {
    if(queryParams === null) {
      return;
    }
    setIsLoanding(true);
    const res = await jsonp({
      url: url,
      data: queryParams
    });
    setData(res);
    setIsLoanding(false);
  }

  // 只要queryParams改变,就发起请求
  useEffect(()=> {
    fetchData();
  }, [queryParams]);


  // 供外部调用
  const doGet = (params) => {
    setQueryParams(params);
  }

  return {
    isLoading,
    data,
    doGet
  }
}

export default MyFecth;

在主页面中,引用数据请求hooks:

import React, { useState, useEffect} from 'react';
import { Tabs, Input, RangeTime, Button, Table } from './components';
import MyFecth from './MyFetch';

const App = () => {

  // ①使用数据请求hooks
  const { isLoading, data, doGet } = MyFecth('http://xxx');
  
  // 数据类型
  const tabs = [{ key: 1, value: '类型1' }, { key: 0, value: '类型2' }];
  const [tab, setTab] = useState(1);
  // 数据ID
  const [dataId, setDataid] = useState('');
  // 标题
  const [title, setTitle] = useState('');
  // 时间区间, 默认为至今一周时间
  const now = Date.now();
  const [timeRange, setTimeRange] = useState([now - 1000 * 60 * 60 * 24 * 7, now]);
  // 数据列表
  const [dataList, setDataList] = useState([]);
  
  
  
  // 点击搜索按钮
  function handleBtnClick() {
    // ②点击按钮后请求数据
    const params = {};
    title && (params.title = title);
    dataId && (params.dataId = dataId);
    params.startTime = String(timeRange[0]);
    params.endTime = String(timeRange[1]);
    doGet(params);
  }
  
  // ③data改变后,重新渲染列表。
  // 这里相当于 componentDidUpdate。当data发生改变时,重新渲染页面
  useEffect(() => {
    setDataList(data);
  }, [data]);
  
  // ④首次进入页面时,无任何筛选项。拉取数据,渲染页面。
  // useEffect第二个参数为一个空数组,相当于在 componentDidMount 时执行该「副作用」
  useEffect(() => {
    doGet({});
  }, []);


  return <section className="app">
    <Title title="数据查询" />
    <Tabs label="类型" tabs={tabs} tab={tab} onChange={setTab} />
    <Input value={dataId} placeholder="请输入数据ID" onChange={setDataid}>ID</Input>
    <Input value={title} placeholder="请输入数据标题" onChange={setTitle}>标题</Input>
    <TimeRange label="数据时间" value={timeRange} onChange={handleTimeChange}/>
    <article className="btn-container">
      <Button type="primary" isLoading={isLoading} onClick={handleBtnClick}>
        查询          
      </Button>
    </article>
    <Table dataList={dataList}></Table>
  </section>
};

关于React Hooks的一些思考

使用hooks写完这个需求,最直观的感受就是,代码写起来很爽。不需要像以前那样写很多的setState。其次就是

hooks的api设计得很优秀,一个useState的就能将【状态】和【变更状态的逻辑】两两配对。React的基本思想就是【数据到视图的映射】,在hooks中,使用useEffect来表明其中的【副作用】,感觉react官方也倾向于不区分componentDidMount和componentDidUpdate。

从api设计就能看出,hooks提倡组件状态细粒度地拆分。在一个hooks组件中,可能包含很多的状态,如果用户的某些操作,需要同时修改两个状态,那么我需要分别调用这两个状态的修改逻辑,这样会导致组件被重新render两次。而在使用class写法的组件中,只需要一次setState就好。这样看来,hooks中render两次的操作,可能会带来些许的性能问题 ? 这就要求我们在设计组件结构和state时,多斟酌,多抽象。

关于hooks的一些FAQ,官方也有很棒的文档:https://reactjs.org/docs/hooks-faq.html

写在后面

本文通过工作中的一个小需求,完成了一次react hooks的实践,不过上述代码依然有很多需要优化的地方。这次实践让我最直观的接触了react hooks,也帮助自己进一步理解了react团队的一些思想。符合预期。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript Cookie 直接浏览网站分网址
Dec 08 Javascript
JavaScript调用Activex控件的事件的实现方法
Apr 11 Javascript
读JavaScript DOM编程艺术笔记
Nov 15 Javascript
jquery动态更换设置背景图的方法
Mar 25 Javascript
快速学习jQuery插件 Cookie插件使用方法
Dec 01 Javascript
简单对比分析JavaScript中的apply,call与this的使用
Dec 04 Javascript
完美实现八种js焦点轮播图(上篇)
Jul 18 Javascript
详解JSON Web Token 入门教程
Jul 30 Javascript
Swiper.js实现移动端元素左右滑动
Sep 08 Javascript
vue使用高德地图点击下钻上浮效果的实现思路
Oct 12 Javascript
微信小程序新闻网站详情页实例代码
Jan 10 Javascript
element中table高度自适应的实现
Oct 21 Javascript
es6数值的扩展方法
Mar 11 #Javascript
Vue实现一个图片懒加载插件
Mar 11 #Javascript
使用Jenkins部署React项目的方法步骤
Mar 11 #Javascript
vue基础之v-bind属性、class和style用法分析
Mar 11 #Javascript
配置eslint规范项目代码风格
Mar 11 #Javascript
vue基础之事件简写、事件对象、冒泡、默认行为、键盘事件实例分析
Mar 11 #Javascript
vue基础之事件v-onclick=&quot;函数&quot;用法示例
Mar 11 #Javascript
You might like
php&amp;java(一)
2006/10/09 PHP
php面向对象 字段的声明与使用
2012/06/14 PHP
PHP判断JSON对象是否存在的方法(推荐)
2016/07/06 PHP
PHPCrawl爬虫库实现抓取酷狗歌单的方法示例
2017/12/21 PHP
ext combox 下拉框不出现自动提示,自动选中的解决方法
2010/02/24 Javascript
基于JQUERY的多级联动代码
2012/01/24 Javascript
JavaScript中的null和undefined解析
2012/04/14 Javascript
javascript重写alert方法的实例代码
2013/03/29 Javascript
javascript解决innerText浏览器兼容问题思路代码
2013/05/17 Javascript
Jquery 在页面加载后执行的几种方式
2014/03/14 Javascript
纯javascript判断查询日期是否为有效日期
2015/08/24 Javascript
jquery移动端TAB触屏切换实现效果
2020/12/22 Javascript
全面解析Bootstrap中transition、affix的使用方法
2016/05/30 Javascript
js实现滑动到页面底部自动加载更多功能
2017/02/15 Javascript
jQuery简介_动力节点Java学院整理
2017/07/04 jQuery
Nginx 配置多站点vhost 的方法
2018/01/07 Javascript
详解vue-cli 快速搭建单页应用之遇到的问题及解决办法
2018/03/01 Javascript
使用Vue的slot插槽分发父组件内容实现高度复用、更加灵活的组件(推荐)
2018/05/01 Javascript
JavaScript折半查找(二分查找)算法原理与实现方法示例
2018/08/06 Javascript
微信小程序搭建自己的Https服务器
2019/05/02 Javascript
解决echarts图表使用v-show控制图表显示不全的问题
2020/07/19 Javascript
python中使用smtplib和email模块发送邮件实例
2014/04/22 Python
Python使用arrow库优雅地处理时间数据详解
2017/10/10 Python
Python callable()函数用法实例分析
2018/03/17 Python
tensorflow saver 保存和恢复指定 tensor的实例讲解
2018/07/26 Python
Python函数参数操作详解
2018/08/03 Python
Python3将jpg转为pdf文件的方法示例
2019/12/13 Python
Internal修饰符有什么含义
2013/07/10 面试题
司机职责范本
2014/03/08 职场文书
环保建议书作文
2014/03/12 职场文书
初中升旗仪式演讲稿
2014/05/08 职场文书
承诺书范文
2014/06/03 职场文书
中秋手机店促销方案
2014/06/16 职场文书
机电一体化应届生求职信
2014/08/09 职场文书
html+css实现滚动到元素位置显示加载动画效果
2021/08/02 HTML / CSS
Android中View.post和Handler.post的关系
2022/06/05 Java/Android