Hook的使用规则
只能在函数的最外层去使用,不要在循环中或者子函数中去调用
只能在react的函数组件中去调用,也可以在自定义的hooks中去调用
useState
useState 其实就是个状态逻辑函数,通过数组的解构方式去获取一个值和对应这个值的操作方法
const [xxx,setXxx] = useState('defaultValue')
并且第二个参数是个赋值函数,也可以去调用自定义函数去运行
相对于class组件中的优点
- 在状态管理中颗粒度更细
- 代码相对与class而言也比较清晰
- 容易做状态分类
- 采用平铺的写法
Props.children也可以采用这样的写法
const Parent = props => {
const [count, setCount] = useState(0);
return props.children(count, setCount);
};
const TestPage = () => {
return (
<Parent>
{(count, setCount) => {
return (
<button onClick={() => {
setCount(count + 1);
}}
>
clickNum {count}
</button>
);
}}
</Parent>
);
};
useEffect
useEffect 就是指明react在对dom进行更改后,需要运行的函数
因为hooks属于无状态的组件,所以也没有class组件生命周期一说
- 也可用于做优化页面性能
- 可以使用useEffect去模拟class的生命周期(简单理解来说)
useEffect第二个参数是所依赖的值(props传入的值),数组形式,可以写多个
它会判断props的传值和他的上次进行一次浅比较,如果发现有变化,才回去执行,无变化,则不执行。
useEffect(()=>{
console.log('do something')
},['depValue'])
模拟类的didMount
useEffect(()=>{ console.log('do something') },[])
如需清除副作用,可以直接在回调函数中return出一个处理函数
useEffect(()=>{
console.log('do something')
return ()=>{
console.log('clear effect')
}
})
副作用:指当前hooks在函数作用域以外所处理的事情
UseContext
无需使用组件嵌套的形式,就可以订阅react的上下文
换而言之 传统组建通信,数据流基本都是props向下派发的,但是context 可以直接无视子组件嵌套层级与底层的子组件直接通信
典型例子就是redux 就是使用react提供的context的技术做的数据管理
使用UseContext的例子
const ctx = React.createContext();
const myContext = useContext(ctx);
const SubComponent = ()=>{
const {count,setCount} = useContext(myContext);
return <button
onClick={()=>{
setCount(coun+1)
}}
>
{count}
</button>
}
const App = ()=>{
const [count,setCount] = useState(0);
return <ctx.provider
value={{
count,
setCount,
}}
>
<div>
<div>
<subComponent />
</div>
</div>
</ctx.provider>
}
useReducer
useReducer 自定义state 和redux类似
useReducer 返回一个state和dispatch方法,后者用于修改前者的值
useReducer 参数描述
第一个参数 是处理函数 用于disptach后区分操作类型
第二个参数 用于当前state的默认值 init初始值 (initialArg)
第三个参数 作用与当前的state,相当于init (initialArg),是 一个函数需要将 init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被设置为 init(initialArg)。
示例
const reducer = (state, action) => {
switch (action.type) {
case "acc": return { ...state, count: state.count + 1 };
case "ded": return { ...state, count: state.count - 1 };
case "save": save(123);
default: return state;
}
};
const save = state => state;
const TestPage = () => {
const [state, dispatch] = useReducer(reducer,
{
count: 1,
data:
},
save
//这个save方法可以单独抽离出来 进行逻辑判断 搭配useReducer的第三个参数使用,
);
return (
<button onClick={() => {
dispatch({
type: "acc"
});
}}
>
{state.count}
</button>
);
};
useMemo
避免在每次渲染时都进行高开销的计算
缓存计算结果的值(写法类型useEffect)
如果props的依赖值没有发生变化 函数不会执行, 缓存上次计算的状态
传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于useEffect 的适用范畴,而不是 useMemo。
如果没有提供依赖项数组,useMemo
在每次渲染时都会计算新的值。
示例
useMemo(()=>{
console.log('do something')
//复杂的逻辑计算
},[value])
useCallBack
useCallBack 缓存函数
第一个参数是回调函数
第二个是更新依赖项, 依赖项为空则直接缓存 ,反之依赖项发生变化 执行回调
传入子组件的的函数会被重新声明 使用useCallBack进行缓存
useMemo和useCallback的区别
useMemo 计算结果是 return 回来的值, 主要用于 缓存计算结果的值 ,应用场景如: 需要 计算的状态
useCallback 计算结果是 函数, 主要用于 缓存函数,应用场景如: 需要缓存的函数,因为函数式组件每次任何一个 state 的变化 整个组件 都会被重新刷新,一些函数是没有必要被重新刷新的,此时就应该缓存起来,提高性能,和减少资源浪费。
useRef
useRef会返回一个可变的ref对象 直接插入使用 ref.current值为当前dom
useImperativeHandle
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中
useLayoutEffect
useLayoutEffect的执行时机是浏览器把内容真正渲染到界面之前和 componentDidMount 等价。相比于useEffect不会有闪烁的问题;
为什么会有闪烁的问题·
useEffect是dom渲染完毕后去异步执行的,如果在这个过程中在触发重新渲染,就会导致原本渲染的内容再被渲染一次,从而出现闪烁的现场。而useLayoutEffect相当于渲染之前同步进行的,等它这次操作执行完毕后在进行渲染,所以不会闪烁。
useDebugValue
useDebugValue 打印日志到react-dev-tools 第二个参数为可选为一个格式化参数,接受debug的值作为参数,并且返回一个格式化的值