六:以理论结合实践方式梳理前端 React 框架 ——— React 钩子函数

Hook 钩子作用

Hook 是 react 16.8 新增特性,可以说 Hook 是 react 的未来,很有必要深入理解

react 声明组件的方式有两种:一种是类组件;一种是函数组件,在 react 16.8 之前,通常声明组件的方式是类(class)的方式,参考如下:

import React, { Component } from 'react';
class HeadComponent extends Component {
    constructor() {
        super();
        this.state = { name: 'zhangsan' };
    }
    render() {
        const { name } = this.state;
        return <span>{name}</span>
    }
}

这个组件单单只渲染了一个 span 打印一个名字,代码就如此复杂,如果是大型组件,就很难进行拆分和重构,相关业务逻辑需要重复性的分散到组件的各个方法中,react 团队希望,组件不应该变得复杂,最好就是简单的数据流的管道,开发者只需要组合管道即可,所以组件的最佳写法应该是函数,而不是类

import React from 'react';
function HeadComponent(props) {
    const { name } = props;
    return <span>{name}</span>
}

但是这种写法有最大限度,必须是纯的函数,不能包含状态,只能通过 props 属性传值,也不支持生命周期,因此没办法完全取代类组件,react Hooks 的设计目的,就是加强函数组件,让开发者完全不需要使用 “类” 的方式声明组件,就能写出一个具备类组件所有功能的函数组件

react Hooks 默认提供的四个常用钩子函数:

  • useState() 状态钩子
  • useContext() 共享钩子
  • useReducer() 动作钩子
  • useEffect() 副作用钩子

Hook 钩子状态

useState() 状态钩子:用于为函数组件引入状态(state),纯函数不能有状态,所以把状态放在钩子里面

import React, { useState } from 'react';
function HeadComponent() {
    const [total, setTotal] = useState(1);
    return <button>+{total}</button>
}

useState() 接受一个参数,这个参数用于赋值状态的初始值,返回一个数组,第一个值是一个变量,指向当前的状态,第二个值是一个函数,用来更新状态,通常以 set + 变量采用小驼峰命名法

Hook 共享钩子

在状态提升中讲到过 Context,用来处理比较复杂的组件之间进行传值问题,回顾一下:

const { Provider, Consumer } = React.createContext();
function ToolHead() {
	return (
		<Consumer>
			{ (name) => <span>{name}</span> }
		</Consumer>
	)
}
function ToolFoot() {
	return (
		<Consumer>
			{ (name) => <span>{name}</span> }
		</Consumer>
	)
}
function Container() {						// 定义了一个容器组件
	return (
		<div>
			<ToolHead />
			<ToolFoot />
		</div>
	)
}
class APP extends React.Component {
	render() {
		let name = '小人头';
		return (<Provider value={name}><Container /></Provider>)
	}
}

基于 useContext() 来引用共享数据传值,相当于应用了 Consumer 对象

import React, { useState, useContext } from 'react';
import ToolHead from '../components/ToolHead';
import ToolFoot from '../components/ToolFoot';
const AppContext = React.createContext({});
function ToolHead() {
    const { username, handName } = useContext(AppContext);
    return (
    	<div>
        	<span>{username}</span>
            <button onClick={() => handName('木头人')}>改名</button>
        </div>
    );
}
function ToolFoot() {
    const { username } = useContext(AppContext);
    return (
    	<div>
        	<span>{username}</span>
        </div>
    );
}
function Container() {
    const [username, setUsername] = userState('小人头');
	return (
		<AppContext.Provider value={{ username, handName: val => setUsername(val) }}>
			<ToolHead />
			<ToolFoot />
		</AppContext.Provider>
	)
}

Hook 动作钩子

react 本身不提供状态管理功能,通常需要使用外部库,最常用的是 ReduxRedux 的核心概念是:组件发出的 action 与状态管理器的通信,状态管理器接受到 action 后,使用 Reducer 函数算出新的状态

import React, { useReducer } from 'react';
const hocReducer = (state, action) {
    const handAction = {
        "plus": (state) => { return {...state, count: state.count + 1} },
        "cuts": (state) => { return {...state, count: state.count - 1} },
    };
    return handAction[action.type] ? handAction[action.type](state) : state;
}
function HeadComponent() {
    const [state, dispatch] = useReducer(hocReducer, {count: 0});
    const handPlus = () => dispatch({ type: 'plus' });
    const handCuts = () => dispatch({ type: 'cuts' });
    return (
    	<div>
        	<span>结果:{state.count}</span><br />
            <button onClick={handPlus}>+1</button>
            <button onClick={handCuts}>-1</button>
        </div>
    )
}

Hook 生命钩子

useEffect() 用来引入具有副作用的操作,最常见的就是向服务器请求数据,接受两个参数,第一个参数为函数,用于处理界面异步操作,例:向服务器请求数据;第二个参数是一个数组,用于给出 Effect 的依赖项,只要这个数组发生变化,useEffect() 就是执行,如果只传递一个参数,useEffect() 相当于 componentDidMount() 生命周期函数,如果传递了第二个参数,useEffect() 相当于 componentDidUpdate() 生命周期函数

import React, { useEffect } from 'react';
function HeadComponent() {
    useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/posts').then(response => {
           console.log(response); 
        });
    }, []);
    return (
    	<div>
        	<span>结果:小人头</span>
        </div>
    )
}

Hook 定制钩子

Hooks 代码可以进行封装起来,变成一个自定义的 Hooks,便于共享引用

import React, { useEffect, useState } from 'react';
const usePerson = (id) => {
    const [person, setPerson] = useState(null);
    const [personId, setPersonId] = useState(null);
    useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/posts').then(response => {
           	console.log(response); 
            let person = response.filter(item => item.id === id);
            person = person.length > 0 ? person[0] : {};
            useState(person);
            setPersonId(id);
        });
    }, [id]);
    return [personId, person];
}
const Person = () => {
    const [personId, person] = usePerson(1);
    return (
    	<div>
        	<span>id: {personId}</span><br />
        	<span>title: {person.title}</span><br />
        	<span>body: {person.body}</span>
        </div>
    )
}

Hook 路由钩子

学习路由配置的时候,知道 react-router-dom 从 V5+ 开始使用 useHistory() 钩子函数来获得 history 对象

useHistory() 也是一个钩子函数,用于访问可用于导航的 history 实例对象

history 是值history 程序包,是 react router 仅有的两个主要依赖项之一,提供了几种不同的实现,来在各种环境中管理 javascript 中的会话历史记录:

  • browser history:特定于 DOM 的实现,在支持 HTML5 历史记录 API 的 Web 浏览器中很有用
  • hash history:遗留 Web 浏览器的 DOM 特定实现
  • memory histor:内存历史记录实现,可用于测试和像 react native 这样的非 DOM 环境
import React from 'react';
import { useHistory } from 'react-router-dom';
function HomeButton() {
    let history = useHistory();
    const handLink = () => history.push('/');
    return <button onClick={handLink}>首页</button>
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值