第一期:谈谈react hooks

hello,我是海海。我的微信公众号是:海海前端

这一期我们来讲讲React Hooks。阅读时间5~10分钟

欢迎转载,请注明原文和作者

有任何不对的地方,欢迎发消息给我

本期大纲:

  • useEffect和类组件生命周期
  • useEffect/useLayoutEffect/useInsertionEffect:都是干啥的?
  • useStateMobx:这两者也有关系?
  • useStateuseReducer:谁更胜一筹?
  • useCallbackuseMemo:有卵用?

useEffect和类组件生命周期

面试题中常考的useEffect类比类组件生命周期

FC组件第一次渲染之后,触发useEffectsetUp回调函数,这里对应componentDidMount

FC组件二次渲染之后,才会触发useEffectsetUp回调函数,这里对应componentDidUpdate

FC组件被dom移除,会调用useEffectsetUp回调函数的返回值,这个返回值是一个cleanup函数。通常用于清理定时器、解除事件绑定、取消订阅等,这里对应componentWillUnMount

需要注意的是:react组件在重渲染的时候,先使用老的依赖值运行cleanup,再执行setup回调函数。参考原文的Parameters的setup部分

useEffect/useLayoutEffect/useInsertionEffect:都是干啥的?

什么?你还没听过这三个hooks、是时候表演真正的技术了!

比较点 useEffect useLayoutEffect useInsertionEffect
组件渲染 之后 之后 之前
浏览器repaint 之后 之前 之前
啥时候用? 大部分的不会立即改变ui的场景: fetch, eventlistener 发生UI闪烁时 css in js

css in js: 就是在js中动态的创建css样式

useState和Mobx:这两者也有关系?

是不是常常在组件里面到处用useState?或者别人写的useState太多,你想点击离职按钮?没关系,让我们使用Mobx来解决这个问题

Mobx(Mobx State Tree)是一个用于状态管理的JavaScript库。那么他能为useState做些什么呢?

  • 可维护:将组件的state抽离到Mobx
  • 响应式:用observer包裹组件,实现数据响应式

我们看一个Mobx结合Context的例子:

Store

import { createContext, useContext } from 'react'
import { makeAutoObservable } from 'mobx'
class Store {
  constructor() {
    makeAutoObservable(this)
  }
  name: string
  setName(name) {
    this.name = name
  }
}
export const StoreContext = createContext<Store | null>(null)
export const useStore = () => {
  const store = useContext(StoreContext)
  if (!store) {
    throw new Error('useStore must be used in StoreProvider')
  }
  return store
}

export default Store

Father组件:使用StoreContextStore

import Children from './Children.tsx'
import Store, { StoreContext } from './store'
const Father: FC<IProps> = (props) => {
  const store = useLocalObservable(() => new Store())
  reutrn (
    <StoreContext.Provider value={store}>
      <Children></Children>
    </StoreContext.Provider >
  )
}
export default observer(Father)

Children组件:使用useStore

import { useStore } from './store'
const Children: FC<IProps> = (props) => {
  const { name } = useStore()
  return (
    <span>{name}</span>
  )
}
export default observer(Index)

useState和useReducer:谁更胜一筹?

Mobx,我们还可以使用useReducer代替useState

组件state比较少的情况下,用useReducer,会增加复杂度。而当state很多时,并且状态之间会有关联的情况下,可以使用useReducer。

import { useReducer } from 'react'
const reducer = (state, action) => {
  switch (action.type) {
    case 'signIn': {
      ...
      return
    }
    case 'signOut': {
      ...
      return
    }
    default: return
  }
}
const Index: FC<IProps> = (props) => {
  const [loginInfo, dispatch] = useReducer(reducer, {
    userName: '',
    password: ''
  })
  return (
    <div>
      <button onClick={dispatch({ type: 'signIn' })}>登录</button>
      <button onClick={dispatch({ type: 'signOut' })}>登出</button>
    </div>
  )
}

需要注意的是:

  • useReducerreducer函数必须是纯函数
  • 第三个参数是一个函数,用init(initialArg)来设置initialArg,如果未指定,则用initialArg
  • 在严格模式下,React 会调用你的reducer和init两次,其中一个调用结果将被忽略
  • action是用户执行的操作,它可以是任何类型的值。按照约定,操作通常是一个对象,其属性标识它, type 也可以选择具有附加信息的其他属性
  • 如果在调用 dispatch 函数后读取状态变量,则仍将获得调用前屏幕上的旧值

参考原文useReducer

useCallback和useMemo:有卵用?

当你的面试官问你:“确实,按照理论来说,这两个hooks是这样用的。但是,你知道他们的实际应用场景是怎么样的吗?”

“他们在一般情况下,没有任何卵用。所以可以删除他。”你自信的回答道。

你的面试官满意的笑了笑,说:“你被录用了”。

让我们来看看useCallbackuseMemo到底是干嘛的?

一般来说,useCallback是用来缓存匿名函数的,useMemo是用来缓存对象或者组件的。

Well,这只是第一步。

让我们看看实际的情况下,大多数的组件是否会按照我们的设想,缓存组件和函数。

App组件

const App = () => {
  const [count, setCount] = useState<number>(0)
  return (
    <div>
      <Father count={count} />
      <button onClick={() => setCount(count + 1)}>点击添加</button>
    </div>
  )
}

Father组件

interface IProps {
  count: number
}
const Father: FC<IProps> = (props) => {
  const [name, setName] = useState<string>('')
  const setVisible = useCallback(() => {})
  const Son = useMemo(() => {
    return <div></div>
  }, [])
  useEffect(() => {
    setName(海海 + count)
  }, [props.count])
  return (
    <div>
      <Children setVisible={setVisible} name={name} />
      <Son />
    </div>
  )
}

上面的Father组件中缓存了一个setVisible函数给Children组件,缓存了一个Son组件。当我们点击App组件的“点击添加”按钮时,会发生什么?

  • App组件的count改变,触发App组件重渲染
  • 递归重渲染Father组件,注意到,虽然我们缓存了Son,但是Father因为count变了,整个函数便被重新执行,于是useMemo失效了
  • 同时由于name会因为count的改变而改变,所以Children组件也会被重新渲染,那么之前缓存的setVible会被重新执行,于是useCallback失效了

只有当前组件的所有属性都被缓存时,才可以使用useCallback缓存函数
只有当父组件的所有属性都被缓存时,才可以使用useMemo缓存子组件或对象


感谢你的耐心阅读,如果觉得好的话,可以给我点个赞吗

创作不易,感谢你的支持!

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYND8wMr' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片