1.react-hooks解决的问题
-
函数组件中不能拥有自己的状态(state).在hooks之前函数组件是无状态的,都是通过props来获取父组件的状态,但是hooks提供了useState来维护组件内部的状态。
-
函数组件中不能监听组件的生命周期。useEffect聚合了多个生命周期函数。
-
class组件中生命周期较为复杂。
-
class组件逻辑难以复用(HOC,render props)
class的弊端:你必须理解JavaScript中的this的工作方式,这与其他语言存在巨大的差异,代码也非常冗余,class也不能很好的压缩,并且会使热重载出现不稳定的情况。
Hook 使你在非 class 的情况下可以使用更多的 React 特性
2. hooks对比 class的好处
- 写法更加的简洁
- 业务代码更加的聚合,让代码更加的居中好记,方便我们管理
- 逻辑复用方便
3. react函数式组件通信方式
- 父传子:使用props
- 子传父:也是使用props,不过父组件上绑定的是回调函数
- 跨组件之间的通信使用creatContext,useConftext
4. hooks 常用的API使用
-
useState
const [value, setValue] = useState(0)
数组的第一个值是声明的状态,第二个值是状态的改变函数
-
setState是同步的还是异步的(具体原因请点击这里)
-
react18 版本之前,setState在同步环境下异步执行,异步环境下同步执行。
-
react18版本之后,无论是在同步环境还是异步环境中,setState都是异步的。
setSate之所以会设置成异步是为了合并短时间内的多次渲染。
-
-
-
useEffect
useEffect接受一个回调函数以及依赖项,当依赖项发生变化时才会执行里面的回调函数。useEffect类似与class组件的didMount,didUpdata,willUnmount的生命周期
注意点
- useEffect是一步的在组件渲染完成后才会执行
- useEffect的回调函数只能返回一个清除作用的处理函数或者不返回
- 如果use Effect传入的依赖项是空数组那么useEffect内部的函数只会执行一次
-
useMemo, useCallback
useMemo和useCallback主要用于减少组件的更新次数,优化组件性能的。
- useMemo接受一个回调函数以及依赖项,只有依赖项变化时才会重新执行回调函数。优化针对于当前组件高开销的计算
useMome总结:(详细查看:useMome)
-
useMome 是用来缓存计算属性的,它会在发现依赖未改变的情况下返回旧的计算属性值的地址。
-
useMomo绝不是用的越多越好,缓存这项技术本身也需要成本。
-
使用场景:
- 只需要给用巨大计算量的计算属性缓存即可,小的计算量就不需要了
- 当计算属性被传入子组件,并且子组件使用了react.memo进行了缓存的时候,为了避免子组件不必要的渲染时使用。
useCallback总结:(详细查看:useCallback)
-
useCallBack接受一个回调函数以及依赖项 ,并且返回该回调函数的memorize版本,只有依赖项重新变化时才会重新新的momorize版本,不变的时候返回的回调函数是同一个地址引用。优化针对于子组件渲染。useCallBack
-
注意:
- useCallBack不要每个函数都包一下,否则就会变成反向优化,useCallback本身就是需要一定的性能的。
- useCallBack并不能阻止函数重新创建,它只能通过依赖决定返回新的函数还是旧的函数,从而在依赖不变的情况下保证函数地址不变。
- useCallBack需要配置React.memo使用。
-
使用场景:
- 在往子组件传入一个函数并且子组件被React.memo缓存了的时候使用。
-
useRef
useRef类似与react.createRef
const node = useRef(null) <input ref={node}/>这样可以通过node.current属性访问到该Dom元素。
注意:useRef创建的对象在组件的整个生命周期内保持不变,也就是说每次重新渲染组件时,返回的ref对象都是同一个(使用React.createRef,每次重新渲染组件都会重新创建ref)
-
useReducer
useReducer类似与redux中的reducer
useReducer传入一个计算函数和初始化state,类似与redux,通过返回的state我们可以访问状态,通过dispatch可以对状态做修改
const initstate = 0; function reducer(state, action) { switch (action.type) { case 'increment': return {number: state.number + 1}; case 'decrement': return {number: state.number - 1}; default: throw new Error(); } } function Counter(){ const [state, dispatch] = useReducer(reducer, initstate); return ( <> Count: {state.number} <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ) } 6. useContext
通过useContext我们可以更加方便的获取上层组件提供的context。主要是跨代组件之间的传值
父组件
import React, { createContext, Children } from 'react' import Child from './child' export const MyContext = createContext() export default function Parent() { return ( <div> <p>Parent</p> <MyContext.Provider value={{name: 'cc', age: 21}}> <Child /> </MyContext.Provider> </div> ) } 复制代码子组件
import React, { useContext } from 'react' import { MyContext } from './parent' export default function Parent() { const data = useContext(MyContext) // 获取父组件提供的context console.log(data) return ( <div> <p>Child</p> </div> ) } 复制代码使用步骤
- 父组件创建并导出
context:export const MyContext = createContext() - 父组件使用
provider和value提供值:<MyContext.provide value={{name: 'cc', age: 22}} /> - 子组件导入父组件的
context:import { MyContext } from './parent' - 获取父组件提供的值:
const data = useContext(MyContext)
不过在多数情况下我们都不建议使用
context,因为会增加组件的耦合性。7、useLayoutEffect
useEffect,useLayoutEffect的区别:(具体解释请点击)
- useEffect 在全部渲染完毕后才会执行,是异步执行的。
- useLayoutEffect 会在 Dom创建之后,视图渲染之前执行,并且会阻塞DOM;useLayoutEffect是同步的。
useEffect的使用场景:
- 一般使用useEffect,对Dom的初始化创建的操作时,使用useLayoutEffect.
useLayoutEffect和componentDidMount事等价的。
5. react 生命周期总结
-
constructor()
-
作用:在React组件挂载之前,会调用他的构造函数。
注意:在为 React.Component 子类实现构造函数时,应在其他语句之前调用
super(props)。否则,this.props在构造函数中可能会出现未定义的 bug。 -
使用场景(只用这两种场景):
-
通过给this.state赋值对象来初始化内部的state
-
为事件处理函数绑定实例。
注意:只能在构造函数中直接为
this.state赋值。如需在其他方法中赋值,你应使用this.setState()替代。
-
-
-
componentDidMount()
-
作用:会在组件挂载后(插入DOM中)立即调用。
-
使用场景:
- 依赖于DOM节点的初始化应该放在这里,如网络请求数据
- 添加订阅的好地方,比如redux需要添加订阅(注意:不要忘了在componentDidMount()中取消订阅)
-
-
componentDidUpdate()
-
作用:会在更新后立即调用,首次渲染不会调用。(如果shouldCompontentUpdate()返回false,则不会调用)
-
使用场景:
- props传过来的值,更新前后值不一样,发送网络请求。
-
-
componentWillUnmount()
-
作用:会在组件卸载及销毁之前调用。此方法中执行必要的清理操作。
-
使用场景:
- 清除timer
- 清除创建的订阅
-
- 父组件创建并导出