一、useContext的使用
在之前的开发中,我们要在组件中使用共享的Context有两种方式:
第一种方式:类组件可以通过 类名.contextType = MyContext方式,在类中获取context;
第二种方式:多个Context或者在函数式组件中通过 MyContext.Consumer 方式共享context;
但是多个Context共享时的方式会存在大量的嵌套:
import React, {createContext, useState} from 'react';
import CounterClass from './01-体验hooks/01-counter_class'
import CounterHook from './01-体验hooks/02-counter-hook'
import CounterHook2 from './01-体验hooks/03-counter-hook'
import MultiHookState from "./02-useState的使用/01-多个状态和复杂状态";
import ComplexHookState from './02-useState的使用/02-复杂状态的修改'
import ClassCounterChange from './03-useEffect的使用/01-class实现title的修改'
import HookCounterChange from './03-useEffect的使用/02-hook实现title的修改'
import EffectHookCancelDemo from './03-useEffect的使用/03-useEffect模拟订阅和取消订阅'
import MultiEffectHookDemo from './03-useEffect的使用/04-多个useEffect一起使用'
import ContextHookDemo from './04-useContext的使用/01-useContext的使用'
export const UserContext = createContext()
export const ThemeContext = createContext()
function App() {
const [show, setShow] = useState(true)
return (
<div>
{/*<CounterClass />*/}
{/*<CounterHook />*/}
{/*<CounterHook2 />*/}
{/*<MultiHookState />*/}
{/*<ComplexHookState />*/}
{/*<ClassCounterChange />*/}
{/*<HookCounterChange />*/}
{/*{show && <EffectHookCancelDemo />}*/}
{/*<button onClick={e => setShow(!show)}>切换</button>
{show && <MultiEffectHookDemo />}*/}
<UserContext.Provider value={{name: 'why', age: 18}}>
<ThemeContext.Provider value={{fontSize: "30px", color: "red"}}>
<ContextHookDemo/>
</ThemeContext.Provider>
</UserContext.Provider>
</div>
)
}
export default App
import React from "react";
import {UserContext, ThemeContext} from "../App";
export default function ContextHookDemo() {
return (
<div>
<UserContext.Consumer>
{
user => {
return (
<ThemeContext.Consumer>
{
theme => {
return (
<div>
<div>用户昵称:{user.name}</div>
<div>年龄:{user.age}</div>
<h2>颜色:{theme.color}</h2>
</div>
)
}
}
</ThemeContext.Consumer>
)
}
}
</UserContext.Consumer>
</div>
)
}
Context Hook允许我们通过Hook来直接获取某个Context的值;
注意事项:
- 当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重新渲染,并使用最新传递给 MyContext provider 的 context value 值。
二、useReducer
很多人看到useReducer的第一反应应该是redux的某个替代品,其实并不是。
useReducer仅仅是useState的一种替代方案:
- 在某些场景下,如果state的处理逻辑比较复杂,我们可以通过useReducer来对其进行拆分;
- 或者这次修改的state需要依赖之前的state时,也可以使用;
import React, {useState, useReducer} from "react";
function reducer(state, action) {
switch (action.type) {
case "increment":
return {...state, counter: state.counter + 1}
case "decrement":
return {...state, counter: state.counter - 1}
default:
return state
}
}
export default function Home() {
// const [count, setCount] = useState(0)
const [state, dispatch] = useReducer(reducer, {counter: 0})
return (
<div>
<h2>Home当前计数:{state.counter}</h2>
<button onClick={e => {dispatch({type: "increment"})}}>+1</button>
<button onClick={e => {dispatch({type: 'decrement'})}}>-1</button>
</div>
/*<div>
<h2>Home当前计数:{count}</h2>
<button onClick={e => {setCount(count + 1)}}>+1</button>
<button onClick={e => {setCount(count - 1)}}>-1</button>
</div>*/
)
}
数据是不会共享的,它们只是使用了相同的counterReducer的函数而已。
所以,useReducer只是useState的一种替代品,并不能替代Redux。
三、useCallback
useCallback实际的目的是为了进行性能的优化。
如何进行性能的优化呢?
- useCallback会返回一个函数的 memoized(记忆的) 值;
- 在依赖不变的情况下,多次定义的时候,返回的值是相同的;
案例一:使用useCallback和不使用useCallback定义一个函数是否会带来性能的优化;(答案:不能,因为两者都需要进行函数的创建国出)
案例二:使用useCallback和不使用useCallback定义一个函数传递给子组件是否会带来性能的优化;
以下为未使用useCallback的情况:
以下为使用useCallback的情况:
通常使用useCallback的目的是不希望子组件进行多次渲染,并不是为了函数进行缓存;
import React, {memo, useCallback, useState} from "react";
const HYButton = memo((props) => {
console.log('HYButton重新渲染: ' + props.title)
return <button onClick={props.increment}> HYButton +1</button>
})
export default function CallbackHookDemo02() {
console.log('CallbackHookDemo02重新渲染了')
const [count, setCount] = useState(0)
const [show, setShow] = useState(true)
const increment1 = () => {
console.log('执行increment函数')
setCount(count + 1)
}
const increment2 = useCallback(() => {
console.log('执行increment函数')
setCount(count + 1)
}, [count])
return (
<div>
<h2>CallbackHookDemo02: {count}</h2>
<HYButton title='btn1' increment={increment1} />
<HYButton title='btn2' increment={increment2} />
<button onClick={e => setShow(!show)}>show切换</button>
{/*<button onClick={increment1}>+1</button>
<button onClick={increment2}>+1</button>*/}
</div>
)
}
四、useMemo
useMemo实际的目的也是为了进行性能的优化。
如何进行性能的优化呢?
- useMemo返回的也是一个 memoized(记忆的) 值;
- 在依赖不变的情况下,多次定义的时候,返回的值是相同的;
案例:
- 案例一:进行大量的计算操作,是否有必须要每次渲染时都重新计算; (答案:每次渲染时都重新计算了)
import React, {useMemo, useState} from "react";
function calcNumber(count) {
let total = 0
for (let i = 1; i <= count; i++) {
total += i
}
console.log('for循环执行了')
return total
}
export default function MemoHookDemo01() {
const [count, setCount] = useState(10)
const [show, setShow] = useState(true)
const total = useMemo(() => {
return calcNumber(count)
}, [count])
return (
<div>
<h2>计算数字的累加和:{total}</h2>
<button onClick={e => setCount(count + 1)}>+1</button>
<button onClick={e => setShow(!show)}>show切换</button>
</div>
)
}
- 案例二:对子组件传递相同内容的对象时,使用useMemo进行性能的优化