今日复习计划:不可变量、React18
一. 前端知识
1. React中使用不可变量
为什么React需要不可变量
import { useState} from "react";
import { cloneDeep } from "lodash";
export default function App() {
const [obj, setObj] = useState({ name: "cxm" });
return (
<div>
<button
onClick={() => {
let newObj = cloneDeep(obj);
newObj.name = "cxm2";
setObj(newObj);
}}
>
点击
</button>
<div>{obj.name}</div>
</div>
);
}
在上诉代码中,state的obj为引用型数据类型,当我们需要修改obj的熟悉时我们不可以直接进行修改。在以往的做法中,我们需要使用deepClone之类的库进行创建一个新的对象。当对象较大时,十分影响我们系统的性能。使用immer不可变量既可以优化代码又可以优化性能。
import { useImmer } from "use-immer";
export default function App() {
const [obj, setObj] = useImmer({ name: "cxm" });
return (
<div>
<button
onClick={() => {
setObj((draft) => {
draft.name = "cxm2";
});
}}
>
点击
</button>
<div>{obj.name}</div>
</div>
);
}
2. React18
2.1 RenderApi
18前:
ReactDom.Render(root,<App/>,()=>{
console.log('渲染完成')
})
18:
ReactDom.createRoot(root).render(()=>{
console.log('渲染完成')
return <App/>
})
2.2 setState批量处理
react18之前,在react事件中的setState会批量处理。
// React18之前
import { useState } from "react";
import "./styles.css";
export default function App() {
console.log("app render"); // 会更新1次。
const [count1, setCount1] = useState(1);
const [count2, setCount2] = useState(1);
return (
<div className="App">
<button
onClick={ () => {
setCount1(count1 + 1);
setCount2(count2 + 1);
}}
>
更新
</button>
</div>
);
}
react18之前,在setTimeout、Promise等事件中setState则不会进行批量处理
// React18之前
import { useState } from "react";
import "./styles.css";
export default function App() {
console.log("app render"); // 会更新2次。
const [count1, setCount1] = useState(1);
const [count2, setCount2] = useState(1);
return (
<div className="App">
<button
onClick={ () => {
setCount1(count1 + 1);
setCount2(count2 + 1);
}}
>
更新
</button>
</div>
);
}
React18里,无论在任何时间中,setState都会被批量处理,除了一下情况
// React18里
import { useState } from "react";
import "./styles.css";
export default function App() {
console.log("app render"); // 会更新2次。
const [count1, setCount1] = useState(1);
const [count2, setCount2] = useState(1);
return (
<div className="App">
<button
onClick={aync () => {
await setCount1(count1 + 1); // await会导致不会批量处理
setCount2(count2 + 1);
}}
>
更新
</button>
</div>
);
}
- 在 18 之前,只有在react事件处理函数中,才会自动执行批处理,其它情况会多次更新
- 在 18 之后,任何情况都会自动执行批处理,多次更新始终合并为一次,除非使用了
aync await进了打断
2.3 并发模式
lane
从React17起,React对事件的优先级判断从expirationTime更新为lane。用于判断事件优先级,使用二进制表示,对应十进制为0-31,优先级依次下降。
export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /* */ 0b0000000000000000000000000000000;
export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001;
export const SyncBatchedLane: Lane = /* */ 0b0000000000000000000000000000010;
export const InputDiscreteHydrationLane: Lane = /* */ 0b0000000000000000000000000000100;
const InputDiscreteLanes: Lanes = /* */ 0b0000000000000000000000000011000;
const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000100000;
const InputContinuousLanes: Lanes = /* */ 0b0000000000000000000000011000000;
export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000100000000;
export const DefaultLanes: Lanes = /* */ 0b0000000000000000000111000000000;
const TransitionShortHydrationLane: Lane = /* */ 0b0000000000000000001000000000000;
const TransitionShortLanes: Lanes = /* */ 0b0000000000000011110000000000000;
const TransitionLongHydrationLane: Lane = /* */ 0b0000000000000100000000000000000;
const TransitionLongLanes: Lanes = /* */ 0b0000000001111000000000000000000;
const RetryLanes: Lanes = /* */ 0b0000011110000000000000000000000;
export const SelectiveHydrationLane: Lane = /* */ 0b0000100000000000000000000000000;
const NonIdleLanes = /* */ 0b0000111111111111111111111111111;
export const IdleHydrationLane: Lane = /* */ 0b0001000000000000000000000000000;
const IdleLanes: Lanes = /* */ 0b0110000000000000000000000000000;
export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
useTransition
import { useState, useTransition, useLayoutEffect } from "react";
function App() {
const [value, setValue] = useState("");
const [isPending, startTransition] = useTransition();
const handleValueChange = (e) => {
startTransition(() => setValue(e.target.value));
};
return (
<div className="container">
<input onChange={handleValueChange} />
<div className="list">
{Array(100000)
.fill("a")
.map((item) => (
<div>{value}</div>
))}
</div>
</div>
);
}
export default App;
setValue在useTransition的回调中执行,触发了并发更新。被setTransition包含的setState的UI更新会被标记为不紧急更新,反正会优先执行紧急事件:onClick、onScroll等。
2.4 Suspense与React.lazy实现代码分包
import React, { Suspense } from "react";
import "./styles.css";
const OtherComponent = React.lazy(() => import("./otherComponent"));
export default function App() {
return (
<div className="App">
<Suspense>
<OtherComponent></OtherComponent>
</Suspense>
</div>
);
}
二. 算法
无
三. 面经
无
四. 其他
He said, one day you’ll leave this world behind,
so live a life you will remenber