我与hooks的这一年, 万字长文总结

effect 每次完成渲染之后触发, 配合 array 去模拟类的生命周期

  • 如果不传,则每次 componentDidUpdate 时都会先触发 returnFunction(如果存在),再触发 effect

  • [] 模拟 componentDidMount

  • [id] 仅在 id 的值发生变化以后触发

  • 清除 effect

useEffect(() => {

ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange);

return () => {

ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange);

};

});

useLayoutEffect

  • 跟 useEffect 使用差不多,通过同步执行状态更新可解决一些特性场景下的页面闪烁问题

  • useLayoutEffect 会阻塞渲染,请谨慎使用 对比看看 

import React, { useLayoutEffect, useEffect, useState } from ‘react’;

import ‘./App.css’

function App() {

const [value, setValue] = useState(0);

useEffect(() => {

if (value === 0) {

setValue(10 + Math.random() * 200);

}

}, [value]);

const test = () => {

setValue(0)

}

const color = !value  ? ‘red’ : ‘yellow’

return (

<React.Fragment>

点我

</React.Fragment>

);

}

export default App;

useContext

const context = useContext(Context)

useContext 从名字上就可以看出,它是以 Hook 的方式使用 React Context, 先简单介绍 Context 的概念和使用方式

import React, { useContext, useState, useEffect } from “react”;

const ThemeContext = React.createContext(null);

const Button = () => {

const { color, setColor } = React.useContext(ThemeContext);

useEffect(() => {

console.info(“Context changed:”, color);

}, [color]);

const handleClick = () => {

console.info(“handleClick”);

setColor(color === “blue” ? “red” : “blue”);

};

return (

<button

type=“button”

onClick={handleClick}

style={{ backgroundColor: color, color: “white” }}

toggle color in Child

);

};

// app.js

const App = () => {

const [color, setColor] = useState(“blue”);

return (

<ThemeContext.Provider value={{ color, setColor }}>

Color in Parent: 

</ThemeContext.Provider>

);

};

useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init)

语法糖跟 redux 差不多,放个基础 ???

function init(initialCount) {

return {count: initialCount};

}

function reducer(state, action) {

switch (action.type) {

case ‘increment’:

return {count: state.count + 1};

case ‘decrement’:

return {count: state.count - 1};

case ‘reset’:

return init(action.payload);

default:

throw new Error();

}

}

function Counter({initialCount}) {

const [state, dispatch] = useReducer(reducer, initialCount, init);

return (

<>

Count: {state.count}

<button

onClick={() => dispatch({type: ‘reset’, payload: initialCount})}>

Reset

<button onClick={() => dispatch({type: ‘increment’})}>+

<button onClick={() => dispatch({type: ‘decrement’})}>-

</>

);

}

useRef

const refContainer = useRef(initialValue);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变

  • 解决引用问题–useRef 会在每次渲染时返回同一个 ref 对象

  • 解决一些 this 指向问题

  • 对比 createRef – 在初始化阶段两个是没区别的,但是在更新阶段两者是有区别的。

  • 我们知道,在一个局部函数中,函数每一次 update,都会在把函数的变量重新生成一次。所以我们每更新一次组件, 就重新创建一次 ref, 这个时候继续使用 createRef 显然不合适,所以官方推出 useRef。useRef 创建的 ref 仿佛就像在函数外部定义的一个全局变量,不会随着组件的更新而重新创建。但组件销毁,它也会消失,不用手动进行销毁

总结下就是 ceateRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用

useMemo

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

一个常用来做性能优化的 hook,看个 ???

const MemoDemo = ({ count, color }) => {

useEffect(() => {

console.log(‘count effect’)

}, [count])

const newCount = useMemo(() => {

console.log(‘count 触发了’)

return Math.round(count)

}, [count])

const newColor = useMemo(() => {

console.log(‘color 触发了’)

return color

}, [color])

return 

{count}

{newCount}

{newColor}

}

我们这个时候将传入的 count 值改变 的,log 执行循序

count 触发了

count effect

  • 可以看出有点类似 effect, 监听 a、b 的值根据值是否变化来决定是否更新 UI

  • memo 是在 DOM 更新前触发的,就像官方所说的,类比生命周期就是 shouldComponentUpdate

  • 对比 React.Memo 默认是是基于 props 的浅对比,也可以开启第二个参数进行深对比。在最外层包装了整个组件,并且需要手动写一个方法比较那些具体的 props 不相同才进行 re-render。使用 useMemo 可以精细化控制,进行局部 Pure

useCallback

const memoizedCallback = useCallback(

() => {

doSomething(a, b);

},

[a, b],

);

useCallback 的用法和上面 useMemo 差不多,是专门用来缓存函数的 hooks

// 下面的情况可以保证组件重新渲染得到的方法都是同一个对象,避免在传给onClick的时候每次都传不同的函数引用

import React, { useState, useCallback } from ‘react’

function MemoCount() {

const [value, setValue] = useState(0)

memoSetCount = useCallback(()=>{

setValue(value + 1)

},[])

return (

<button

onClick={memoSetCount}

Update Count

{value}

)

}

export default MemoCount

自定义 hooks


自定义 Hook 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook 一般我将 hooks 分为这几类

util

顾名思义工具类,比如 useDebounce、useInterval、useWindowSize 等等。例如下面 useWindowSize

import { useEffect, useState } from ‘react’;

export default function useWindowSize(el) {

const [windowSize, setWindowSize] = useState({

width: undefined,

height: undefined,

});

useEffect(

() => {

function handleResize() {

setWindowSize({

width: window.innerWidth,

height: window.innerHeight,

});

}

window.addEventListener(‘resize’, handleResize);

handleResize();

return () => window.removeEventListener(‘resize’, handleResize);

},

[el],

);

return windowSize;

}

API

像之前的我们有一个公用的城市列表接口,在用 redux 的时候可以放在全局公用,不用的话我们就可能需要复制粘贴了。有了 hooks 以后我们只需要 use 一下就可以在其他地方复用了

import { useState, useEffect } from ‘react’;

import { getCityList } from ‘@/services/static’;

const useCityList = (params) => {

const [cityList, setList] = useState([]);

const [loading, setLoading] = useState(true)

const getList = async () => {

const { success, data } = await getCityList(params);

if (success) setList(data);

setLoading(false)

};

useEffect(

() => {getList();},

[],

);

return {

cityList,

loading

};

};

export default useCityList;

// bjs

function App() {

// …

const { cityList, loading } = useCityList()

// …

}

logic

逻辑类,比如我们有一个点击用户头像关注用户或者取消关注的逻辑,可能在评论列表、用户列表都会用到,我们可以这样做

import { useState, useEffect } from ‘react’;

import { followUser } from ‘@/services/user’;

const useFollow = ({ accountId, isFollowing }) => {

const [isFollow, setFollow] = useState(false);

const [operationLoading, setLoading] = useState(false)

const toggleSection = async () => {

setLoading(true)

const { success } = await followUser({ accountId });

if (success) {

setFollow(!isFollow);

}

setLoading(false)

};

useEffect(

() => {

setFollow(isFollowing);

},

[isFollowing],

);

return {

isFollow,

toggleSection,

operationLoading

};

};

export default useFollow;

只需暴露三个参数就能满足大部分场景

UI

还有一些和 UI 一起绑定的 hook, 但是这里有点争议要不要和 ui 一起混用。就我个人而言一起用确实帮我解决了部分复用问题,我还是分享出来。

import React, { useState } from ‘react’;

import { Modal } from ‘antd’;

// TODO 为了兼容一个页面有多个 modal, 目前想法通过唯一 key 区分,后续优化

export default function useModal(key = ‘open’) {

const [opens, setOpen] = useState({

});

const onCancel = () => {

setOpen({ key: false });

};

const showModal = (type = key) => {

setOpen({ [type]: true });

};

const MyModal = (props) => {

return 

};

return {

showModal,

MyModal,

};

}

// 使用

function App() {

const { showModal, MyModal } = useModal();

return <>

展开

</>

}

逻辑跨端


最近听了第十五届的 D2 大会当轩大佬的《跨端的另一种思路》——Write Once 的分享,核心就是如何渲染、如何布局等 UI 层面的变化要远远大于业务逻辑层面,甚至是小程序和 Flutter,其大致的开发范式都没有发生太大的改变,Flutter 开发范式和 React 非常相似,同样是声明式 UI,同样存在 VirtualDOM。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

整理面试题,不是让大家去只刷面试题,而是熟悉目前实际面试中常见的考察方式和知识点,做到心中有数,也可以用来自查及完善知识体系。

《前端基础面试题》,《前端校招面试题精编解析大全》,《前端面试题宝典》,《前端面试题:常用算法》PDF完整版点击这里免费领取

前端面试题宝典

前端校招面试题详解

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-TVqnCN8f-1713807003322)]

[外链图片转存中…(img-UmzcY0Jz-1713807003322)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-a6HB3Nyg-1713807003323)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

[外链图片转存中…(img-LNA9GJIg-1713807003323)]

最后

整理面试题,不是让大家去只刷面试题,而是熟悉目前实际面试中常见的考察方式和知识点,做到心中有数,也可以用来自查及完善知识体系。

《前端基础面试题》,《前端校招面试题精编解析大全》,《前端面试题宝典》,《前端面试题:常用算法》PDF完整版点击这里免费领取

[外链图片转存中…(img-sQXSiWLY-1713807003323)]

[外链图片转存中…(img-byY3w6r9-1713807003323)]

[外链图片转存中…(img-2R9BUQxK-1713807003324)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值