前端框架react----hook基础

前端框架react----hook基础


目录

前端框架react----hook基础

前言

一、基本

1、Hook初识

2、注意点

二、基础Hook

1、useState

2、useEffect

3、useContext

三、其他Hook

1、useReducer

2、useRef

3、useCallback

4、useMemo

四、自定义Hook


前言

经过前面的学习,本文将讲解一下Hook的比较重要的知识点。

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

虽然在学习 Hook 的过程中了解 class 组件并不是必须的,但是如果你想更快更容易地理解 Hook 还是需要先了解 class 组件的。

一、基本

1、Hook初识

希望大家代码可以自己敲哦,下面的代码截图展示,以及结果:

 这是一个简单的Hook,当我们点击按钮的时候,页面上的数字递增,同时控制台也会打印出不同的信息,最直观的感觉,我们再也不需要定义class类来使用state维护组件自身的状态了,而是使用useState来生成组件的state和控制它的方法,同样的没有借助组件的生命周期,我们注册在useEffect中的方法在首次加载和state更新的时候也执行了,在这里,useState与useEffect就是不同的Hook。通过在函数中调用不同的Hook,就可以实现使用class实现的一些功能。

2、注意点

  • Hook 是一些可以在函数组件里钩入React state 及生命周期等特性的函数。不能在 class 组件中使用

  • 只能在函数最外层调用 Hook 。不要在循环、条件判断或者子函数中调用

  • 只能在React的函数组件或自定义Hook中调用Hook

  • Hook是一种复用状态逻辑的方式,它不复用state本身,Hook的每次调用都有一个完全独立的state,简单来说就是一个新的state

  • Hook使用了JavaScript的闭包机制

二、基础Hook

1、useState

const [state, setState] = useState(initialState)

这句代码的含义,首先我们要知道,useState主要用来返回一个state数组,可以看到定义了两个参数,一个是state,另一个是setState,在第一次渲染的时候,返回的state等于默认值initialState,setState用来更新state,在后续的渲染中,useState返回的值都会是更新后的state。

特性:

  • useState 是一个函数,返回值是一个数组(当前 state 以及更新 state 的函数), 唯一的参数就是初始 state

  • 初始渲染期间,返回的状态 (state) 与传入的第一个参数值相同

  • setState函数用于更新state。它接收一个新的state值并将组件的一次重新渲染加入队列

  • initiaState只会在初次渲染中起作用,后续会被忽略,如果传入一个函数就只会在初始渲染时被调用,如果 为空,变量的值就是undefined。

//这种情况下第一次渲染name就为undefined
const [name, setName] = useState()

name // undefined

// 这种情况下这个函数只会执行一次
const [count, setCount] =useState(()=> {
    const initialState = someExpensiveComputation(props);
    return initialState;
})

   \huge \cdot  更新state变量总是替换它而不是合并它,this.setstate()会自动合并

//比如我们修改state中的某一个属性

const [state,setState] = useState({
    name:'小杨',
    age:23,
    hobby:'打篮球'
})

//使用class
this.setState({
    age:18
})

//使用Hook
setState(prevState => {
    return {...prevState,age:17}
})

    \huge \cdot  可以多次声明

另外,在使用useState声明变量的时候,我们可以单独声明每一个变量,也可以直接使用一个对象或数组。

//单独声明
const [height, setHeight]=useState(10)
const [width, setWidth]=useState(10)
const [left, setLeft] = useState(10)
const [top, setTop] = useState(10)

// 也可以直接使用一个对象
const [state, setState] = useState({
    height: 10,
    width: 20,
    left: 10,
    top: 10
})

 在实际的使用中,按照逻辑将state分组是最佳实践,避免了state对象过于臃肿也很好的将有关联的state进行了分组维护。比如,上面声明的几个变量我们可以这样进行分类

const [box, setBox] = useState({
    height: 10,
    width: 20
})

const [position, setPosition] = useState({
    left: 10,
    top: 10
})

2、useEffect

该 Hook 接收一个包含命令式、且可能有副作用代码的函数。

useEffect(() => {
    effect
    return () => {
        cleanup
    };
}, [input])

特点:

  • 默认情况下,它在第一次渲染之后和每次更新之后都会执行

  • 可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合

// 这个函数会在首次加载、state更新以及组件卸载的时候执行
useEffect(() => {
    console.log('方法执行了')
    return () => {
        console.log('解绑了')
    }
})
  • 与componentDidMount或componentDidUpdate不同,使用useEffect调度的effect不会阻塞浏览器更新屏幕,也就是说它是异步的

  • 可以使用多个effect用来分离不同的逻辑(比如按照不同的用途),也就是说我们可以添加多个effect

  • 可以配置effect的第二个参数来设置依赖项,当这个依赖项改变的时候再去执行这个函数,从而实现性能优化,如果我们只想让这个函数在首次加载和卸载的时候执行,那么可以传入一个空数组

// 只有在 count 变化的时候,函数才会执行
useEffect(() => {
    console.log('方法执行了')
    return () => {
        console.log('解绑了')
    }
}, [count]) 

// 只在首次加载和卸载的时候执行
useEffect(() => {
    console.log('方法执行了')
    return () => {
        console.log('解绑了')
    }
}, []) 
  • 必须在依赖中包含所有effect中用到的组件内的值

  • 清楚函数会在组件卸载前执行。如果组件多次渲染(通常如此),则在执行下一个effect之前,上一个effect就已被清除

  • 如果只想在更新的时候运行effect,那么可以使用一个可变的ref手动存储一个boolean值来判断

  • effect拿到的总是定义它的那次渲染中的props和state

3、useContext

const value = useContext(MyContext);

如果忘记了context,可以查看我之前博客,有关context的介绍,复习复习。

特性:

  • 接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值

  • useContext 的参数必须是 context 对象本身

  • 当前的context值由上层组件中距离当前组件最近的<MyContext.Provider>的value prop决定

  • 调用了useContext的组件总会在context值变化时重新渲染

// 官方文档的案例,省去中间组件
const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
}

const ThemeContext = React.createContext(themes.light);

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  )
}

三、其他Hook

1、useReducer

useState 的替代方案,如果熟悉 Redux ,那么理解 Reducer 就很容易了

接收一个形如 `(state, action) => newState` 的 `reducer`,并返回当前的 `state` 以及与其配套的 `dispatch` 方法

 

  • reducer 本质是一个纯函数,每次只返回一个值,那个值可以是数字,字符串,对象,数组或者对象,但是它总是一个值

  • React 会确保 dispatch 函数的标识是稳定的,并且不会在组件重新渲染时改变

  • useReducer还能给那些会触发深更新的组件做性能优化,因为可以向子组件传递dispatch而不是回调函数

  • reducer更合适去处理比较复杂的state,来维护组件的状态

上面示例是一种基础初始化 state 的方式,我们也可以选择 惰性初始化 的方式

// init 是一个函数,返回值就是 state
const [state, dispatch] = useReducer(reducer, initialArg, init)

如果使用这种方式初始化,state 的值就是 init(initialArg)

2、useRef

const refContainer = useRef(initialValue)
  • useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。

  • 返回的 ref 对象在组件的整个生命周期内保持不变,可以很方便地保存任何可变值

  • 变更 .current 属性不会引发组件重新渲染

  • useRef() 创建的是一个普通的 Javascript 对象,并且每次渲染返回的都是同一个对象

注意点:

在理解 useRef 之前,我们一定要清楚的是对于函数组件而言,每一次状态的改变都是会重新触发 render。也就是说,我们在组件状态变化的时候拿到的值已经是一个全新的数据,只是 react 帮我们记住了之前的数据

利用 ref 对象的这个特性,我们可以实现:

  • 比如之前说过的 只在更新时运行 effect

  • 获取上一轮的 propsstate

  • 访问子组件变得很容易

3、useCallback

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
)

函数组件的每一次调用都会执行内部的所有逻辑,带来较大的性能损耗,所以 useCallback 出现了,它的作用就是解决性能问题。需要使用到缓存函数的地方,都是 useCallback 的应用场景

最常见的场景就是父组件传递给子组件的函数,props 中的某个依赖项不发生变化的情况下,使用 useCallback 使子组件不必执行更新

将内联函数和依赖项数组作为参数传入 useCallback,该回调函数仅在某个依赖项改变时才会更新,从而实现性能优化

  • 会在组件第一次渲染和依赖项更新的时候执行

  • 返回一个缓存的函数

  • 不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作

  • 如果没有提供依赖项数组,useCallback 在每次渲染是都会执行;如果是一个空数组,那么就只会在首次渲染的时候计算一次

4、useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])

useCallback 一样,作为性能优化的方式存在。与 useCallback 不同的是:useMemo 返回的是一个缓存的值

  • 会在组件第一次渲染和依赖项更新的时候去重新计算缓存的值

  • 返回一个缓存的值

  • 不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作

  • 如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值,如果是一个空数组,那么就只会在首次渲染的时候计算一次

四、自定义Hook

通过自定义 Hook,可以将组件逻辑提取到可重用的函数中

hook 之前,我们一般会使用 render props 和 高阶函数来共享组件之间的状态逻辑

现在,我们可以使用自定义 Hook 的方式来实现同样的功能,而且可以使逻辑条理更加清晰

  • 自定义 Hook 是一个函数,其名称以 use 开头,函数内部可以调用其他的 Hook

  • 不需要具有特殊的标识。我们可以自由的决定它的参数是什么,以及它应该返回什么

  • 自定义 Hook 是一种重用状态逻辑的机制,并不会共享数据

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  // ...

  return isOnline;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是小先生

知识是无价的,白嫖也可以的。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值