react怎么可以实现watch? - 网站

react怎么可以实现watch?

分类:React入门教程_React框架基础教程 · 发布时间:2020-11-22 20:42 · 阅读:2826

前言

在Vue中,我们经常需要用watch去观察一个值的变化,通过新旧值的对比去做一些事情。

但是React Hook中好像并没有提供类似的hook来让我们实现相同的事情

不过好在Hook的好处就在于它可以自由组合各种基础Hook从而实现强大的自定义Hook。

本篇文章就带你打造一个简单好用的use-watch hooks。

实现

实现雏形

首先分析一下Vue中watch的功能,就是一个响应式的值发生改变以后,会触发一个回调函数,那么在React中自然而然的就想到了useEffect这个hook,我们先来打造一个基础的代码雏形,把我们想要观察的值作为useEffect的依赖传入。

type Callback<T> = (prev: T | undefined) => void;

function useWatch<T>(dep: T, callback: Callback<T>) {
  useEffect(() => {
   callback();
  }, [dep]);
}

现在我们使用的时候就可以

const App: React.FC = () => {
  const [count, setCount] = useState(0);

  useWatch(count, () => {
    console.log('currentCount: ', count);
  })

  const add = () => setCount(prevCount => prevCount + 1)

  return (
    <p>
      <p> 当前的count是{count}</p>
      {count}
      <button onClick={add} className="btn">+</button>
    </p>
  )
}

实现oldValue

在每次count发生变化的时候,会执行传入的回调函数。

现在我们加入旧值的保存逻辑,以便于在每次调用传进去的回调函数的时候,可以在回调函数中拿到count上一次的值。

什么东西可以在一个组件的生命周期中充当一个存储器的功能呢,当然是useRef啦。

function useWatch<T>(dep: T, callback: Callback<T>) {
  const prev = useRef<T>();

  useEffect(() => {
    callback(prev.current);
    prev.current = dep;
  }, [dep]);

  return () => {
    stop.current = true;
  };
}

这样就在每一次更新prev里保存的值为最新的值之前,先调用callback函数把上一次保留的值给到外部。

现在外部使用的时候 就可以

const App: React.FC = () => {
  const [count, setCount] = useState(0);

  useWatch(count, (oldCount) => {
    console.log('oldCount: ', oldCount);
    console.log('currentCount: ', count);
  })

  const add = () => setCount(prevCount => prevCount + 1)

  return (
    <p>
      <p> 当前的count是{count}</p>
      {count}
      <button onClick={add} className="btn">+</button>
    </p>
  )
}

实现immediate

其实到此为止,已经实现了Vue中watch的主要功能了,

现在还有一个问题是useEffect会在组件初始化的时候就默认调用一次,而watch的默认行为不应该这样。

现在需要在组件初始化的时候不要调用这个callback,还是来做,利用一个标志位inited来保存组件是否初始化的标记。

并且通过第三个参数config来允许用户改变这个默认行为。

type Callback<T> = (prev: T | undefined) => void;
type Config = {
  immediate: boolean;
};

function useWatch<T>(dep: T, callback: Callback<T>, config: Config = { immediate: false }) {
  const { immediate } = config;

  const prev = useRef<T>();
  const inited = useRef(false);

  useEffect(() => {
    const execute = () => callback(prev.current);

    if (!inited.current) {
      inited.current = true;
      if (immediate) {
        execute();
      }
    } else {
      execute();
    }
    prev.current = dep;
  }, [dep]);
}

实现stop

还是通过useRef做,只是把控制ref标志的逻辑暴露给外部。

type Callback<T> = (prev: T | undefined) => void;
type Config = {
  immediate: boolean;
};

function useWatch<T>(dep: T, callback: Callback<T>, config: Config = { immediate: false }) {
  const { immediate } = config;

  const prev = useRef<T>();
  const inited = useRef(false);
  const stop = useRef(false);

  useEffect(() => {
    const execute = () => callback(prev.current);

    if (!stop.current) {
      if (!inited.current) {
        inited.current = true;
        if (immediate) {
          execute();
        }
      } else {
        execute();
      }
      prev.current = dep;
    }
  }, [dep]);

  return () => {
    stop.current = true;
  };
}

这样在外部就可以这样去停止本次观察。

const App: React.FC = () => {
  const [prev, setPrev] = useState()
  const [count, setCount] = useState(0);

  const stop = useWatch(count, (prevCount) => {
    console.log('prevCount: ', prevCount);
    console.log('currentCount: ', count);
    setPrev(prevCount)
  })

  const add = () => setCount(prevCount => prevCount + 1)

  return (
    <p>
      <p> 当前的count是{count}</p>
      <p> 前一次的count是{prev}</p>
      {count}
      <button onClick={add} className="btn">+</button>
      <button onClick={stop} className="btn">停止观察旧值</button>
    </p>
  )
}

源码地址:

https://github.com/sl1673495/use-watch-hook

文档地址:

文档是基于docz生成的,配合mdx还可以实现非常好用的功能预览:

https://sl1673495.github.io/use-watch-hoo

标签:
react watch

相关文章

react中怎么使用sass?

方法:1、使用npm工具安装sass-loader和node-sass依赖;2、配置webpack.config.js文件;3、在需要的组件中引入scss,然后添加scss代码即可。

react怎么判断checkbox是否被选中

react判断checkbox是否被选中的方法:可以通过【if ($(&quot;#checkbox-id&quot;).get(0).checked) {}】方法来进行判断。还可以通过原生js方法来进行判断,如【ele.checked】。

react子组件如何向父组件传值?

在react中,首先通过父组件给子组件传递一个函数,然后子组件通过参数传到父组件,通过props来传递函数的引用,并通过回调的方式实现;其实就是子组件调用父组件的方法,把值以形参的方式传出来。

react组件什么时候会重新渲染?

每当组件状态改变时,React就会调用render函数进行重新渲染。更改状态意味着当调用setState函数时,React触发更新;这不仅意味着将调用组件的render函数,而且还意味着重新渲染其所有后续子组件,无论其prop是否已更改。

react组件生命周期有几个阶段?

React组件生命周期有三个阶段:加载、更新和卸载。加载阶段表示一个组件实例被创建并被插入到DOM中;更新阶段表示由状态或属性的改变导致组件的重新渲染;卸载阶段表示组件从DOM中移除。

返回分类 返回首页