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
)
}
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前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合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)]