React整理总结(七、Hooks)

1.Class组件的优缺点

优点
  • class组件可以定义自己的state,用来保存组件自己内部的状态;函数式组件不可以,因为函数每次调用都会产生新的临时变量;
  • class组件有自己的生命周期,我们可以在对应的生命周期中完成自己的逻辑;
    比如在componentDidMount中发送网络请求,并且该生命周期函数只会执行一次; 函数式组件在学习hooks之前,如果在函数中发送网络请求,意味着每次重新渲染都会重新发送一次网络请求;
  • class组件可以在状态改变时只会重新执行render函数以及我们希望重新调用的生命周期函数componentDidUpdate等; 函数式组件在重新渲染时,整个函数都会被执行,似乎没有什么地方可以只让它们调用一次;
缺点
  • 复杂组件变得难以理解
  • 难以理解的class
  • 组件复用状态很难:
    • 高阶组件;
    • redux中connect或者react-router中的withRouter
    • 于Provider、Consumer来共享一些状态
hooks
  • 简单总结一下hooks:
    • 它可以让我们在不编写class的情况下使用state以及其他的React特性;
    • 但是我们可以由此延伸出非常多的用法,来让我们前面所提到的问题得到解决;
  • Hook的使用场景:
    • Hook的出现基本可以代替我们之前所有使用class组件的地方;
    • Hook只能在函数组件中使用,不能在类组件,或者函数组件之外的地方使用;

2. 常用hooks

  • 2.1useState保存状态
const [msg, setMsg] = useState("hello hooks");
  • 2.2useEffect副作用
useEffect(() => {
	// 执行
	return () => {
		// 取消
	}
}, [//依赖项])
  • 2.3useContext(XXXContext)接获取某个Context的值
// context.js
import { createContext } from 'react';

const UserContext = createContext();
const ThemeContext = createContext();

export default {
UserContext, ThemeContext
}

// App.jsx
<UserContext.Provider value={{name: 'xiaoming', age: 18}}>
	<ThemeContext.Provider value={{color: 'red', size: 12}}>
		<App>
	</ThemeContext.Provider>
</UserContext.Provider>

// Function Comp
export default () => {
	const USER = useContext(UserContext);
	const THEME = useContext(ThemeContext);
	
	return (<>
		<h2>{USER.name}-{USER.age}</h2>
		<h3 style={{color: THEME.color, size: THEME.size}}>content</h3>
	</>)
}
  • 2.4userReducer()管理负责数据, useState的替代品,而非redux的替代品
// const [state, dispatch] = userReducer(reducer, initState);

import React, { memo, userReducer } from 'react';

function reducer(state, action){
	switch(action.type){
		case 'add':
			return {...state, counter: state.counter + action.payload};
		case 'sub':
			return {...state, counter: state.counter - action.payload};
		default:
			return state;
	}
}

export default memo(() => {
	const [state, dipatch] = useReducer(reducer, {counter: 0});
	return <>
		<h2>counter: {state.counter}</h2>
		<button onClick={() => dispatch({type: 'add', payload: 5})}>+5</button>
		<button onClick={() => dispatch({type: 'sub', payload: 5})}>-5</button>
	</>
})
  • 2.5 性能优化useCallback记忆化回调函数,useMemo

useCallback会返回一个函数的 memoized(记忆的) 值;在依赖不变的情况下,多次定义的时候,返回的值是相同的;

作为参数传递给子组件时使用;
const fn = useCallback(() => {
	dosomething(a, b);
}, [a, b]);
配合useRef使用;
const [count, setCount]  = useState();
const countRef = useRef();
countRef.current = count;
const addFn = useCallback(() => setCount(countRef.current + 1), []);

useMemo(() ={}, [dep])对回调函数的结果进行缓存

useCallback(fn,[dep]) = useMemo(() => fn, [dep])
- 进行大量的计算操作,是否有必须要每次渲染时都重新计算;
- 对子组件传递相同内容的对象时,使用useMemo进行性能的优化
  • 2.6 useRef返回一个ref对象,返回的ref对象再组件的整个生命周期保持不变。
    • 用于获取dom元素
    • 用于保存具体的值,解决闭包陷阱
  • 2.7 useImperativeHandle子组件向父组件传递特定的对象

const SonComponent = memo(forwardRef((props, ref) => {
	const inputRef = useRef();
	useImperativeHandle(() => {
		return {
			focus(){
				inputRef.current.focus();
			}
			setValue(val){
				inputRef.current.value = val;
			}
		} //返回的这个对象会被绑定到ref.current
	})
	
	return (<>
		<h2>son component<h2>
		<input ref={inputRef}/>
	</>)
}))

const FatherComponent = memo(() => {
	const sonRef = useRef();
	return (<>
		<h1>father comp</h1>
		<SonComponent ref={sonRef} />
	</>)
})
  • 2.8 useLayoutEffect()
    • useEffect会在渲染的内容更新到DOM上后执行,不会阻塞DOM的更新;
    • useLayoutEffect会在渲染的内容更新到DOM上之前执行,会阻塞DOM的更新;

3. 自定义hook

  • 形如useFn,内部可以使用其他hook
// 获取滚动位置
export function useWindomPosition(){
	const [position, setPosition] = useState();
	const handleScroll = () => {
		setPosition(window.scrollY);
	}
	
	useEffect(() => {
		document.addEventListener('scroll', handleScroll);
		return () => {
			document.removeEventListener('scroll', handleScroll);
		}
	})
	
	return position;
}

// 使用localStorage存储数据
export function useLocalStorage(key){
	const [data, setData] = useState(() => JSON.parse(window.localStorage.getItem(key)));
	useEffect(() => {
		window.localStorage.setItem(key, data);
	}, [data]);
	return [data, setData];
}

4.其他hook

  • useSelector将state映射到组件中;useDispatch直接获取dispatch函数;useStore获取store对象;
    • 参数一:将state映射到需要的数据中;
    • 参数二:可以进行比较来决定是否组件重新渲染。如果state中的a发生变化,某个组件只用了state中的b,也会重新渲染,所以需要第二个参数优化。
// 1.获取state
import { useSelector, useDispatch, shallowEqual } from 'react-redux';
const { count } = useSelector((state) => {
	return {
		count: state.counter.count
	}
},shallowEqual)

  • useId用于生成横跨服务端和客户端的稳定的唯一 ID 的同时避免 hydration 不匹配的 hook。
    • useId是用于react的同构应用开发的,前端的SPA页面并不需要使用它;
    • useId可以保证应用程序在客户端和服务器端生成唯一的ID,这样可以有效的避免通过一些手段生成的id不一致,造成
      hydration mismatch;
  • useTransition返回一个状态值表示过渡任务的等待状态,以及一个启动该过渡任务的函数。告诉react对于某部分任务的更新优先级较低,可以稍后进行更新。
  • useDeferredValue接受一个值,并返回该值的新副本,该副本将推迟到更紧急地更新之后。

你可能感兴趣的:(React学习,react.js,前端,javascript)