我与hooks的这一年, 万字长文总结,2024年最新附项目源码

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注前端)
img

正文

// 获取更新后的state

do {

// useState 第一个参数会被转成 useReducer

const action = update.action;

newState = reducer(newState, action);

//按照当前链表位置更新数据

update = update.next;

} while (update !== null);

hook.memoizedState = newState;

// 返回新的 state 以及 dispatch

return [newState, dispatch];

}

}

}

// …

}

结合实际让我们看下面一组 hooks

let isMounted = false

if(!isMounted) {

[name, setName] = useState(“张三”);

[age] = useState(“25”);

isMounted = true

}

[sex, setSex] = useState(“男”);

return (

<button

onClick={() => {

setName(李四");

}}

修改姓名

);

首次渲染时 hook 顺序为

name => age => sex

二次渲染的时根据上面的例子,调用的 hook 的只有一个

setSex

所以总结一下初始化阶段构建链表,更新阶段按照顺序去遍历之前构建好的链表,取出对应的数据信息进行渲染当两次顺序不一样的时候就会造成渲染上的差异。

为了避免出现上面这种情况我们可以安装 eslint-plugin-react-hooks


// 你的 ESLint 配置

{

“plugins”: [

// …

“react-hooks”

],

“rules”: {

// …

“react-hooks/rules-of-hooks”: “error”, // 检查 Hook 的规则

“react-hooks/exhaustive-deps”: “warn” // 检查 effect 的依赖

}

}

useEffect

useEffect(effect, array)

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 一下就可以在其他地方复用了

总结
  • 对于框架原理只能说个大概,真的深入某一部分具体的代码和实现方式就只能写出一个框架,许多细节注意不到。

  • 算法方面还是很薄弱,好在面试官都很和蔼可亲,擅长发现人的美哈哈哈…(最好多刷一刷,不然影响你的工资和成功率???)

  • 在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。

  • 要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!

第一次跳槽十分忐忑不安,和没毕业的时候开始找工作是一样的感受,真的要相信自己,有条不紊的进行。如果有我能帮忙的地方欢迎随时找我,比如简历修改、内推、最起码,可以把烦心事说一说,人嘛都会有苦恼的~

祝大家都有美好的未来,拿下满意的 offer。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
了 hooks 以后我们只需要 use 一下就可以在其他地方复用了

总结
  • 对于框架原理只能说个大概,真的深入某一部分具体的代码和实现方式就只能写出一个框架,许多细节注意不到。

  • 算法方面还是很薄弱,好在面试官都很和蔼可亲,擅长发现人的美哈哈哈…(最好多刷一刷,不然影响你的工资和成功率???)

  • 在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。

  • 要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!

第一次跳槽十分忐忑不安,和没毕业的时候开始找工作是一样的感受,真的要相信自己,有条不紊的进行。如果有我能帮忙的地方欢迎随时找我,比如简历修改、内推、最起码,可以把烦心事说一说,人嘛都会有苦恼的~

祝大家都有美好的未来,拿下满意的 offer。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-5z99IWoM-1713592437841)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值