React学习七(React Hooks)


一、为什么会有Hooks

      React的组件创建方式,一种是类组件,一种是纯函数组件,并且React团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。也就是说组件的最佳写法应该是函数,而不是类。
纯函数组件有着类组件不具备的多种特点:
①纯函数组件没有状态
②纯函数组件没有生命周期
③纯函数组件没有this
      这些特性导致了函数组件,只能做UI展示的功能,涉及到状态的管理与切换,不得不用类组件或者redux,但类组件的也是有缺点的,比如,遇到简单的页面,代码会显得很重,并且每创建一个类组件,都要去继承一个React实例。
      为了解决这种类组件功能齐全却很重,纯函数很轻便却有上文几点重大限制。React队设计了React Hooks,React Hooks就是加强版的函数组件,我们可以完全不使用 class,就能写出一个全功能的组件,实现状态管理。

二、Hooks的含义

      'Hooks’的单词意思为“钩子”。
      React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。而React Hooks 就是我们所说的“钩子”。
注意:你需要写什么功能,就用什么钩子。
      对于常见的功能,React为我们提供了一些常用的钩子,当然有特殊需要,我们也可以写自己的钩子。下面是React Hooks为我们提供的默认的四种最常用钩子:

useState()
useContext()
useReducer()
useEffect()

      不同的钩子为函数引入不同的外部功能,上面四种钩子都带有use前缀,React Hooks约定,钩子一律使用use前缀命名。所以,自己定义的钩子都要命名为useXXX

三、React Hooks的用法

1、useState()

      状态钩子。纯函数组件没有状态,useState()用于为函数组件引入状态。
首先我们使用类组件来写一个简单的计数器.

class Counter extends React.Component{
    constructor(props) {
        super(props);
        this.state= {
            count: 0
        }
    }
    addCount= ()=>{
        let newCount = this.state.count;
        this.setState({
            count: newCount += 1
        })
    }
    render() {
        return (
            <>
                <p>{ this.state.count }</p>
                <br/>
                <button onClick={ this.addCount }>count++</button>
            </>
        )
    }
}

然后使用Hooks写计数器。

import React,{ useState } from "react";

const NewCount = ()=> {
	//引入状态
	const [ count,setCount ] = useState(0)
	//定义内部函数改变状态属性的值
	const addCount= ()=> {
		let newCount = count;
		setCount(newCount +=1);
	}
	return (
		<>
			<p> { count }</p>
			<button onClick={ addCount }>Count++</button>
		</>
	)
}
export default NewCount;

      用函数组件实现了一个功能完全一样的计数器,代码看起来更加的轻便简洁,没有了继承,没有了渲染逻辑,没有了生命周期等。这就是hooks存在的意义。
      在useState()中,它接受状态的初始值作为参数,即上例中计数的初始值,它返回一个数组,其中数组第一项为一个变量,指向状态的当前值,类似this.state;第二项是修改状态属性值的函数,用来更新状态,类似setState。该函数的命名,约定为set前缀加状态的变量名。

2、useContext()

      共享状态钩子。作用就是可以做状态的分发,在React16.X以后支持,避免了react逐层通过Props传递数据。
使用步骤:

//第一步:创建全局的Context
const AppContext = React.createContext([初始化参数])

//第二步:通过全局的Context进行状态值的共享
return (
	<AppContext.Provider value={{属性名:}}>
		<组件1 />
		<组件2 />
	</AppContext>
)

举例如下:

import React,{ useContext } from "react";

const HookTest= ()=>{
    //创建一个全局的Context对象(上下文对象)
    const AppContext = React.createContext({});

    const A= ()=>{
        const { name,age} = useContext(AppContext);
        return (
            <>
                <p>我是A组件,名称是:{ name },年龄:{ age }</p>
            </>
        )
    }

    const B= ()=>{
        const { name,age } = useContext(AppContext);
        return (
            <>
                <p>我是B组件,名称是:{ name },年龄:{ age }</p>
            </>
        )
    }

    return (
        <AppContext.Provider value={{name:'小红',age:25}}>
            <A />
            <B />
        </AppContext.Provider>
    )
}

export default HookTest;

在这里插入图片描述

3、useReducer()

      Action钩子。在使用React的过程中,如遇到状态管理,一般会用到Redux,而React本身是不提供状态管理的。而useReducer()提供了状态管理。首先,关于redux我们都知道,其原理是通过用户在页面中发起action,从而通过reducer方法来改变state,从而实现页面和状态的通信。而Reducer的形式是(state, action) => newstate。Hooks的useReducer()是这样的:

const [state, dispatch] = useReducer(reducer, initialState)

      它接受reducer函数状态的初始值作为参数,返回一个数组,其中第一项为当前的状态值第二项为发送action的dispatch函数
举例如下:使用useReducer()实现一个计数器。

import React, { useReducer } from "react";
const HookReducer = ()=> {
	const reducer = (state,action)=> {
		if (action.type === 'add') {
			return {
				...state,
				count: state.count + 1
			}
		}else {
			return state
		}
	}
	const addCount = ()=> {
		dispatch({
			type: 'add'
		})
	}
	const [state,dispatch ] = useReducer(reducer,{count: 0})
	return (
		<>
			<p>{state.count}</p>
			<button onClick={ addCount }>useReducer</button>
		</>
	)
}
export default HookReducer;

      通过代码可以看到,使用useReducer()代替了Redux的功能,但useReducer无法提供中间件等功能,假如有这些需求,还是需要用到redux。

4、useEffect()

      副作用钩子。可以用来更好的处理副作用,如异步请求等,Hooks的useEffect()也是为函数组件提供了处理副作用的钩子。在类组件中我们会把请求放在componentDidMount里面,在函数组件中我们可以使用useEffect()。其具体用法如下:

 useEffect(() => {},[array])

      useEffect()接受两个参数,第一个参数是要进行的异步操作代码第二个参数是一个数组,用来给出Effect的依赖项,只要这个数组发生变化,useEffect()就会执行。当第二项省略不填时,useEffect()会在每次组件渲染时执行。这一点类似于类组件的componentDidMount。

5、用户自定义的Hooks

      命名的要求:用use开头,后跟名称(首字母大写),作用:根据具体业务的需求,对Hooks中默认的钩子函数进行封装,使代码的结构更加清晰,便于使用和维护。
举例如下:

import React,{ useState,useEffect } from "react";

const usePerson =({name})=>{ //自定义Hooks
    const [loading,setLoading] = useState(true);
    const [person,setPerson ] = useState({});

    useEffect(()=> {
        setLoading(true);
        setTimeout(() => {
            setLoading(false)
            setPerson({name})
        }, 2000)
    },[name]) //第二个参数为默认

    return [loading,person];
}

const AsyncPage= (name)=>{ //只进行UI展示
    const [loading,person] = usePerson(name)
    return (
        <>
            { loading?<p>Loading...</p>:<p>{ person.name }</p> }
        </>
    )
}

const PersonPage= ()=>{
    const [userName,setUserName] = useState('')

    const changeName= (name)=>{
        setUserName(name);
    }
    return (
        <>
            <AsyncPage name={ userName } />
            <br/>
            <button onClick={()=>{ changeName('郭靖')}}>郭靖</button>
            <br/>
            <button onClick={()=>{ changeName('黄蓉')}}>黄蓉</button>
        </>
    )
}

export default PersonPage;

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值