react的常用知识点总结

58 阅读5分钟

学习react学习了已经很久了,在工作中的实践过程中也是实践了两年多。虽然很多时候能够正常的完成相关需求,但是写出代码和写出好的代码还是存在很大的区别。一个好的程序员应该对自己的代码有所追求,而不仅仅是实现功能,更要优雅的实现功能,方便后面的人维护。

    之前写组件的时候很多时候是用类组件,以下是一些常用的生命周期函数。

生命周期

   组件的生命周期 一般分为:挂载阶段,更新阶段,卸载阶段

   组件实例被创建,并插入dom时,生命周期调用如下:

constructor()
getDerivedStateFromProps() // 返回一个对象来更新state,如果返回null则不更新任何内容
render()
componentDIdMount() // 依赖于dom实例化,通常会在这里进行接口的请求

更新阶段

getDerivedStateFromProps() // 返回一个对象来更新state,如果返回null则不更新任何内容
shouldComponentUpdate() // 性能优化的生命周期函数,根据返回值 表示是否需要刷新
render()
getSnapshotBeforeUpdate() // 返回值作为入参传给componentDIdUpdate
componentDIdUpdate() // 在更新后立即调用,可在此处进行网络请求

卸载阶段

componentWillUnmount // 在组件卸载之前调用,多用于清理操作,如清除定时器等

以上就是类组件的所有生命周期函数,但是以下生命周期函数可能在开发过程中造成Bug,应减少使用,(componentWillMount()componentWillUpdate()componentWillReceiveProps()),这类生命周期函数由于react的框架改动,对于更新改为时间片的更新,需要区分事件优先级,这些生命周期函数可能会因为时间片的暂停和执行 而进行多次的执行,造成难以察觉且严重的bug。

 

后面自己再写的时候,就变得用函数组件比较多了。函数组件更加轻巧,而且易于封装,便于拆分。更适用于组件化的思想。下面记录以下react hooks中的一些注意点。

useRef

 ref可用于可记住组件的某些信息,但是又不想触发新的渲染。例如可以用于输入框的聚焦效果。

useRef返回一个一个{current: x} // x为你向useRef传的值。

大多时候我们都会用state来存取变量,一下是state和ref的区别。

refstate
useRef(initialValue)返回 { current: initialValue }useState(initialValue) 返回 state 变量的当前值和一个 state 设置函数 ( [value, setValue])
更改时不会触发重新渲染更改时触发重新渲染。
可变 —— 你可以在渲染过程之外修改和更新 current 的值。“不可变” —— 你必须使用 state 设置函数来修改 state 变量,从而排队重新渲染。
你不应在渲染期间读取(或写入) current 值。你可以随时读取 state。但是,每次渲染都有自己不变的 state 快照

 

什么时候需要用到useRef?

  1. 存储timeout id

2.存储和操作dom

3.存储不需要被用来计算 JSX 的其他对象

 

默认情况下,组件不暴露其 DOM 节点。 您可以通过使用 forwardRef 并将第二个 ref 参数传递给特定节点来暴露 DOM 节点。

如果你尝试将 ref 放在 你自己的 组件上,例如 <MyInput />,默认情况下你会得到 null。下面是 MyInput 如何使用 forwardRef API:

const MyInput = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});

 

useEffect

这边记录一下使用useEffect自己踩得一些坑。

实现功能是播放器的功能,播放器的话,播放和暂停是触发play() 和 pause() 方法,然后还有一个进度条的展示,然后我初步展示的时候,是用一个变量来定义进度条百分比。这样结构就有一定的弊端,一个内容,却用两个变量进行维护,十分的冗余。

所以可以用一个ref保存变量,通过useEfftct来判断是否播放来调用相关方法。

import { useState, useRef, useEffect } from 'react';

function VideoPlayer({ src, isPlaying }) {
  const ref = useRef(null);

  useEffect(() => {
    if (isPlaying) {
      ref.current.play();
    } else {
      ref.current.pause();
    }
  });

  return <video ref={ref} src={src} loop playsInline />;
}

export default function App() {
  const [isPlaying, setIsPlaying] = useState(false);
  return (
    <>
      <button onClick={() => setIsPlaying(!isPlaying)}>
        {isPlaying ? '暂停' : '播放'}
      </button>
      <VideoPlayer
        isPlaying={isPlaying}
        src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
      />
    </>
  );
}

 

依赖数组中可以省略ref

React 保证 每轮渲染中调用 useRef 所产生的引用对象时,获取到的对象引用总是相同的,即获取到的对象引用永远不会改变,所以它不会导致重新运行 Effect。

 useEffect的一些注意事项

  • 与事件不同,Effect 是由渲染本身,而非特定交互引起的。
  • Effect 允许你将组件与某些外部系统(第三方 API、网络等)同步。
  • 默认情况下,Effect 在每次渲染(包括初始渲染)后运行。
  • 如果 React 的所有依赖项都与上次渲染时的值相同,则将跳过本次 Effect。
  • 不能随意选择依赖项,它们是由 Effect 内部的代码决定的。
  • 空的依赖数组([])对应于组件“挂载”,即添加到屏幕上。
  • 仅在严格模式下的开发环境中,React 会挂载两次组件,以对 Effect 进行压力测试。
  • 如果 Effect 因为重新挂载而中断,那么需要实现一个清理函数。
  • React 将在下次 Effect 运行之前以及卸载期间这两个时候调用清理函数。
  • 如果你可以在渲染期间计算某些内容,则不需要使用 Effect。
  • 想要缓存昂贵的计算,请使用 useMemo 而不是 useEffect
  • 想要重置整个组件树的 state,请传入不同的 key
  • 想要在 prop 变化时重置某些特定的 state,请在渲染期间处理。
  • 组件 显示 时就需要执行的代码应该放在 Effect 中,否则应该放在事件处理函数中。
  • 如果你需要更新多个组件的 state,最好在单个事件处理函数中处理。
  • 当你尝试在不同组件中同步 state 变量时,请考虑状态提升。
  • 你可以使用 Effect 获取数据,但你需要实现清除逻辑以避免竞态条件。

对于一些高昂的计算,应该使用useMemo而不是useEffect.

const result = useMemo(() => {
// 这里是一些复杂的计算
return XX
}, [])