useContext()基本使用
import { createContext } from "react";
const Theme = createContext();
const User = createContext();
export { Theme, User };
import ReactDOM from "react-dom/client";
import App from "./pages-learn-hooks/useContext使用/App";
import { Theme, User } from "./context";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<User.Provider value={{ name: "wzm", age: 21 }}>
<Theme.Provider value={{ color: "blue", fontSize: "30px" }}>
<App />
</Theme.Provider>
</User.Provider>
);
import React, { memo, useContext } from "react";
import { Theme, User } from "../../context";
const App = memo(() => {
const user = useContext(User);
const theme = useContext(Theme);
return (
<div>
<h2>useContext App</h2>
<div>
user:{user.name}-{user.age}
</div>
<div style={{ color: theme.color, fontSize: theme.fontSize }}>theme</div>
</div>
);
});
export default App;
useReducer()了解
import React, { memo, useReducer } from "react";
function reducer(state, action) {
//逻辑代码太多,会造成reducer函数逻辑难以维护
switch (action.type) {
case "add":
return { ...state, count: state.count + 1 };
case "sub":
return { ...state, count: state.count - 1 };
case "add_num":
return { ...state, count: state.count + action.num };
case "sub_num":
return { ...state, count: state.count - action.num };
default:
return state;
}
}
const App = memo(() => {
const [state, dispatch] = useReducer(reducer, { count: 0, ikun: [], user: {} });
// 使用useReducer()就不用写多个useState()了,第二个参数是state默认值
// const [count, setCount] = useState();
// const [ikun, setIkun] = useState();
// const [user, setUser] = useState();
return (
<div>
<h2>useReducer Page</h2>
<div>
<h2>当前计数:{state.count}</h2>
<button onClick={(e) => dispatch({ type: "add" })}>+1</button>
<button onClick={(e) => dispatch({ type: "sub" })}>-1</button>
<button onClick={(e) => dispatch({ type: "add_num", num: 5 })}>+5</button>
<button onClick={(e) => dispatch({ type: "sub_num", num: 5 })}>-5</button>
<button onClick={(e) => dispatch({ type: "add_num", num: 100 })}>+100</button>
</div>
</div>
);
});
export default App;
useCallback()
useCallback性能优化的点:
- 当需要将一个函数传递给子组件时,最好使用useCallback进行优化,将优化之后的函数,传递给子组件
import React, { memo, useCallback, useState } from "react";
const App = memo(() => {
const [count, setCount] = useState(0);
// 闭包陷阱:useCallback
const increment = useCallback(
function () {
console.log("increment");
setCount(count + 1);
},
[count]
);
return (
<div>
<h2>useCallback useMemo App Page </h2>
<button onClick={increment}>+1({count})</button>
</div>
);
});
function foo(name) {
function bar() {
console.log(name);
}
return bar;
}
const bar1 = foo("zm");
bar1(); //zm
bar1(); //zm
const bar2 = foo("ww");
bar2(); //ww
bar1(); //zm
export default App;
import React, { memo, useCallback, useState } from "react";
const ZMPage = memo((props) => {
const { increment } = props;
console.log("ZMPage render");
return (
<div>
<button onClick={increment}>ZMPage increment+1</button>
{/* 很多子组件 */}
</div>
);
});
const App = memo(() => {
const [count, setCount] = useState(0);
const [msg, setMsg] = useState("hello ww");
// 闭包陷阱:useCallback
const increment = useCallback(
function () {
console.log("increment");
setCount(count + 1);
},
[count]
);
//只依赖count,父组件改变msg之后子组件不会重新渲染,
//普通函数会重新渲染,因为会重新定义函数,传递的是新函数,子组件props改变,重新渲染
// 普通函数
// const increment = () => {
// setCount(count + 1)
// }
return (
<div>
<h2>useCallback useMemo App Page </h2>
<button onClick={increment}>App +1({count})</button>
<ZMPage increment={increment} />
<h2>msg:{msg}</h2>
<button onClick={(e) => setMsg(Math.random())}>changeMsg</button>
</div>
);
});
export default App;
继续优化,上面count发生改变,子组件仍然要重新渲染,如果子组件有很多页面,都会重新渲染,如何优化呢?
- 方法1:将count依赖移除掉,缺点:闭包陷阱
- 方法2:useRef,在组件多次渲染时,返回的是同一个值
import React, { memo, useCallback, useRef, useState } from "react";
const ZMPage = memo((props) => {
const { increment } = props;
console.log("ZMPage render");
return (
<div>
<button onClick={increment}>ZMPage increment+1</button>
{/* 很多子组件 */}
</div>
);
});
const App = memo(() => {
const [count, setCount] = useState(0);
const [msg, setMsg] = useState("hello ww");
// 闭包陷阱:useCallback
// const increment = useCallback(
// function () {
// console.log("increment");
// setCount(count + 1);
// },
// [count]
// );
// 进一步优化
// 方法1:将count依赖移除掉,缺点:闭包陷阱
// 方法2:useRef,在组件多次渲染时,返回的是同一个值
const countRef = useRef();
countRef.current = count;
const increment = useCallback(function () {
console.log("increment");
setCount(countRef.current + 1);
}, []);
// 普通函数
// const increment = () => {
// setCount(count + 1)
// }
return (
<div>
<h2>useCallback useMemo App Page </h2>
<button onClick={increment}>App +1({count})</button>
<ZMPage increment={increment} />
<h2>msg:{msg}</h2>
<button onClick={(e) => setMsg(Math.random())}>changeMsg</button>
</div>
);
});
export default App;
这样修改count,msg,子组件都不会重新渲染了
useMemo()函数使用
import React, { memo, useMemo, useState } from "react";
const HelloWorld = memo(function (props) {
console.log("HelloWorld render");
return <h2>HelloWorld</h2>;
});
function calcNumTotal(num) {
console.log("calcNumTotal的计算过程被调用~");
let total = 0;
for (let i = 0; i < num; i++) {
total += i;
}
return total;
}
const App = memo(() => {
const [count, setCount] = useState(0);
// 1.不依赖任何的值,进行计算,calcNumTotal只会调用一次
// const result = useMemo(() => {
// return calcNumTotal(10);
// }, []);
// 2.依赖count
const result = useMemo(() => {
return calcNumTotal(count * 2);
}, [count]);
// 3.useMemo(值)和useCallback(函数)的对比
// function fn() {} 下面二者写法等价
// const increment = useCallback(fn, []);
// const increment2 = useMemo(() => fn, []);
// 4.使用useMemo对组件渲染进行优化
// const info = { name: "zm", age: 21 }; //改变count组件重新渲染,字面量是新的,props更新,子组件会被重新渲染
const info = useMemo(() => ({ name: "zm", age: 21 }), []);
return (
<div>
<h2>useMemo App Page</h2>
<div>
计算结果:{result}
<button onClick={(e) => setCount(count + 1)}>+1({count})</button>
<HelloWorld result={result} info={info} />
</div>
</div>
);
});
export default App;
useRef()使用
- useRef绑定DOM
import React, { memo, useRef } from "react";
const App = memo(() => {
const titleRef = useRef();
const inputRef = useRef();
function showTitleDOM() {
console.log(titleRef.current);
inputRef.current.focus();
}
return (
<div>
<h2 ref={titleRef}>useRef App Page</h2>
<input type="text" ref={inputRef} />
<button onClick={showTitleDOM}>查看title的dom</button>
</div>
);
});
export default App;
- useRef绑定值,解决闭包陷阱问题
import React, { memo, useCallback, useRef, useState } from "react";
const ValueRefCpn = memo(() => {
const [count, setCount] = useState(0);
// 通过useRef解决闭包陷阱
const countRef = useRef();
countRef.current = count;
const add = useCallback(() => {
setCount(countRef.current + 1);
// setCount(count + 1); //闭包陷阱 0 + 1 = 1
}, []);
return (
<div>
<h2> ValueRefCpn Page</h2>
<button onClick={(e) => setCount(count + 1)}>+1</button>
<button onClick={add}>+1({count})</button>
</div>
);
});
export default ValueRefCpn;