从实际开发的角度去看react的新特性hooks

React v16.7.0-alpha中加入的新特性Hooks。它可以让你在函数式组件中使用state和生命周期。本人花了点时间研究了下,发现网上大部分的教程都是偏向于理论,或者干脆翻译官网和代码,缺少实际使用场景的教程,所以本人根据自己的理解写了这篇从开发角度去看这个hooks新特性(高手勿拍)

前言

理论方面的我不会讲太多,大家可以搜一搜,非常多的文章。或者直接去看官网。我主要会讲我在项目开发中会怎么使用它。

hooks是干什么的

简单的来说,就是让你的函数式无状态组件,支持使用状态组件的state和生命周期。另外可以解决this绑定这个麻烦的东西。(代码量也会减少很多)

常用的都有什么

相对我开发中常用的hooks大致有useState、useReducer、useEffect。另外还有一些我自定义的hooks。

直接开始用hooks

接下来我们直接开始用,跳过令人头疼的理论,直接在使用中理解他们到底是干什么的。

首先我们需要一个基于react的开发框架,这里打个小广告,推荐自己前段时间分享的一篇文章《如何搭建一个REACT全家桶框架》

在原先的userInfo页面里面进行一个常规查询列表功能的编写。不用hooks功能的写法大致如下: (后面的例子都是基于antd,如何添加支持和按需加载,请看官网文档或者我上传的代码配置,就不细说与hooks无关的东西了)

import React, {PureComponent} from 'react';
import {connect} from 'react-redux';
import {getUserInfo} from "actions/userInfo";
import { Input, Button, List } from 'antd';
import style from './index.less'

// class组件
class UserInfo extends PureComponent {
    constructor(props) {
        super(props);
        // state初始化
        this.state = {
            title: ""
        };
    }

    componentDidMount(){
    // 解构state
        const { title } = this.state;
        this.doSearch(title);
    }

    doSearch = (title) => {
        this.props.getUserInfo(title);
    }

    handleChange=(e) => { 
        // 更新state
        this.setState({
            title:e
        })
    }

    render() {
        const { list=[] } = this.props.userInfo;
        return (
            <div className={style.userInfo}>
                <p>
                    标题:<Input style={{width:'100px'}} onChange={this.doSearch} />
                    <Button  type="primary" onClick={this.doSearch}>查询</Button>
                </p>
                <List
                    header={<div>列表</div>}
                    footer={null}
                    bordered
                    dataSource={list}
                    renderItem={item => (<List.Item>{item}</List.Item>)}
                />
            </div>
        )
    }
}

export default connect((userInfo) => userInfo, {getUserInfo})(UserInfo);
复制代码

从上面代码中,我们看到了state三个相关的地方,初始化---更新---解构获取,接下来我们使用hooks来写。

import React, { useState, useEffect } from 'react';
import {connect} from 'react-redux';
import {getUserInfo} from "actions/userInfo";
import { Input, Button, List } from 'antd';
import style from './index.less'

// 函数式组件
const UserInfo = (props) => {
    
    // 初始化state
    const [title, setTitle] = useState("");
    const [search, setSearch] = useState(false);

    // 查询数据
    useEffect(() => {
        props.getUserInfo(title);
    }, [search]);


    // 参数变化
    const handleChange=(e) => { 
        setTitle(e.target.value);
    }

    // 执行查询
    const doSearch = () => {
        setSearch(!search);
    }

    const { list=[] } = props.userInfo;
    return (
        <div className={style.userInfo}>
            <p>
                标题:<Input style={{width:'100px'}} onChange={(e) => { handleChange(e) }} />
                <Button  type="primary" onClick={() => { doSearch() }}>查询</Button>
            </p>
            <List
                header={<div>列表</div>}
                footer={null}
                bordered
                dataSource={list}
                renderItem={item => (<List.Item>{item}</List.Item>)}
            />
        </div>
    )
    
}

export default connect((userInfo) => userInfo, {getUserInfo})(UserInfo);
复制代码

让我们对比一下,都有哪些不同的地方

  • 统一组件,所有组件都是无状态组件(Funciont)
  • 不再需要绑定this
  • 没有构造函数,内部状态使用useState
  • 没有复杂的生命周期,生命周期使用useEffect(注意这里的参数,它改变就会执行useEffect)
  • 改变state使用它自身提供的setSearch方法

根据上面对比的结果,我们发现,以后写组件只需要写无状态组件了。并且不需要烦恼this。生命周期也不需要写那么多,一个useEffect就够了。并且你灵活控制它的第二个参数,可以决定什么时候去执行它。是不是方便很多。

useReducer对比useState

官网对于内部状态管理,提供了两个方法,另外一个就是useReducer。

如果你熟悉redux的话,你会觉得它很眼熟。我们先写一个,用userReducer来替代useState,然后在来说说为什么用它!

import React, { useReducer, useEffect } from 'react';
import {connect} from 'react-redux';
import {getUserInfo} from "actions/userInfo";
import { Input, Button, List } from 'antd';
import style from './index.less'



function reducer(state, action) {
  switch (action.type) {
    case 'change':
      return {
          ...state,
          ...action.playod
      };
  }
}

const UserInfo = (props) => {
    
    // 初始化reducer
    const initialState = {title: "", search:false};
    const [state, dispatch] = useReducer(reducer, initialState);
 
    // 查询数据
    useEffect(() => {
        props.getUserInfo(state.title);
    }, [state.search]);


    // 参数变化
    const handleChange=(e) => { 
        dispatch({type: 'change', playod:{title:e.target.value}})
    }

    // 执行查询
    const doSearch = () => {
        dispatch({type: 'change', playod:{search:!state.search}})
    }

    const { list=[] } = props.userInfo;
    return (
        <div className={style.userInfo}>
            <p>
                标题:<Input style={{width:'100px'}} onChange={(e) => { handleChange(e) }} />
                <Button  type="primary" onClick={() => { doSearch() }}>查询</Button>
            </p>
            <List
                header={<div>列表</div>}
                footer={null}
                bordered
                dataSource={list}
                renderItem={item => (<List.Item>{item}</List.Item>)}
            />
        </div>
    )
    
}

export default connect((userInfo) => userInfo, {getUserInfo})(UserInfo);
复制代码

用法上和redux相似,通过纯函数和action来执行改变。两个对比之下差距不大,但是根据官方推荐和一些大佬的看法,推荐使用useReducer。

  • 统一管理所有的状态数据
  • 可以处理比较复杂的数据结构

但是个人觉得和redux同时使用的话,对数据存放位置,和两个dispatch的使用比较不友好。各位使用者根据自己的喜好选择吧。

自定义hooks

除了官方提供的hooks,我们还可以自定义一些hooks,这里我就根据我的需求定义一个请求数据的hooks。方便大家理解使用。

src/hooks/request.js

import React, { useEffect, useState } from 'react';
import axios from 'axios';

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

    // 查询数据
    const queryTableData = (params) => {
        setIsLoanding(true);
        axios.post(url).then((res)=>{
            let data = JSON.parse(res.request.responseText);
            const list = data.list.filter((item, index) => {
                return item.indexOf(params) > -1
            })
            setIsLoanding(false);
            setData(list);
        })
    }

    // 根据参数变化决定是否请求数据
    useEffect(() => {
        queryTableData(queryParams);
    }, [queryParams]);

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

    return {
        isLoading,
        data,
        doRequest
    };
} 

export default useSearchData;
复制代码

这里我们写了一个自定义hooks--useSearchData(注意,自定义的hooks要以use开头,切记!!!)。它提供了我们需要的三个结果

  • isLoading 是否在加载
  • data 请求到的结果集
  • doRequest 更换参数再一次请求
src/userInfo/index.js

import React, { useReducer, useEffect } from 'react';
import {connect} from 'react-redux';
import {getUserInfo} from "actions/userInfo";
import { Input, Button, List } from 'antd';
import useSearchData from 'hooks/request'; 
import style from './index.less';



function reducer(state, action) {
  switch (action.type) {
    case 'change':
      return {
          ...state,
          ...action.playod
      };
  }
}

const UserInfo = (props) => {
    
    // 初始化reducer
    const initialState = {title: "", search:false};
    const [state, dispatch] = useReducer(reducer, initialState);
    const {isLoading, data, doRequest} = useSearchData('/api/getList',state.title);
    // 查询数据
    useEffect(() => {
        props.getUserInfo(data);
    }, [data]);


    // 参数变化
    const handleChange=(e) => { 
        dispatch({type: 'change', playod:{title:e.target.value}})
    }

    // 执行查询
    const doSearch = () => {
        doRequest(state.title);
    }

    const { list=[] } = props.userInfo;
    return (
        <div className={style.userInfo}>
            <p>
                标题:<Input style={{width:'100px'}} onChange={(e) => { handleChange(e) }} />
                <Button  type="primary" onClick={() => { doSearch() }}>查询</Button>
            </p>
            <List
                header={<div>列表</div>}
                footer={null}
                loading={isLoading}
                bordered
                dataSource={list}
                renderItem={item => (<List.Item>{item}</List.Item>)}
            />
        </div>
    )
    
}

export default connect((userInfo) => userInfo, {getUserInfo})(UserInfo);
复制代码

在我们的UsesInfo组件中,我们首先调用useSearchData获取isLoading, data, doRequest。在useEffect钩子中根据data来判断是否要更新数据到redux。最后当我们更改查询参数需要更新list的时候,执行doRequest即可。

这样我们的自定义查询hooks就写好了,其实就是把公共的东西抽取出来,封装成一个hooks。尤其是以前的高阶组件和渲染组件,层级嵌套过深,不好维护。写成hooks的形式,都是函数式组件,无嵌套层级。

结尾和GIT地址

本人在项目中常用的hooks就介绍完了,有些人可能觉得加上了useContext是不是完全可以替代redux?个人理解还是不一样,全局的状态管理,最好还是依赖于redux和mobx做管理较好。请各位小伙伴自行体验!!! GIT地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值