React钩子引入了useState来设置组件状态。但是我如何使用钩子来替换下面的回调代码:

setState(
  { name: "Michael" },
  () => console.log(this.state)
);

我想在状态更新后做一些事情。

我知道我可以使用useEffect来做额外的事情,但我必须检查之前的状态值,这需要位代码。我正在寻找一个简单的解决方案,可以使用useState挂钩。


当前回答

如果你想要更新之前的状态,那么你可以在hooks中这样做:

const [count, setCount] = useState(0);


setCount(previousCount => previousCount + 1);

其他回答

我探索了use-state with-callback npm库和其他类似的自定义钩子,但最后我意识到我可以做这样的事情:

const [user, setUser] = React.useState(
  {firstName: 'joe', lastName: 'schmo'}
)

const handleFirstNameChange=(val)=> {
  const updatedUser = {
     ...user,
     firstName: val
  }
  setUser(updatedUser)
  updateDatabase(updatedUser)
}

我写了自定义挂钩与typescript,如果有人还需要它。

import React, { useEffect, useRef, useState } from "react";

export const useStateWithCallback = <T>(initialState: T): [state: T, setState: (updatedState: React.SetStateAction<T>, callback?: (updatedState: T) => void) => void] => {
    const [state, setState] = useState<T>(initialState);
    const callbackRef = useRef<(updated: T) => void>();

    const handleSetState = (updatedState: React.SetStateAction<T>, callback?: (updatedState: T) => void) => {
        callbackRef.current = callback;
        setState(updatedState);
    };

    useEffect(() => {
        if (typeof callbackRef.current === "function") {
            callbackRef.current(state);
            callbackRef.current = undefined;
        }
    }, [state]);

    return [state, handleSetState];
}

我不认为用useRef区分挂载与否是一个好方法,不是一个更好的方法来确定useState()在useEffect()中生成的值是否为初始值?

const [val, setVal] = useState(null)

useEffect(() => {
  if (val === null) return
  console.log('not mounted, val updated', val)
}, [val])

setState()将更改排队到组件状态,并告诉React该组件及其子组件需要使用更新后的状态重新呈现。

setState方法是异步的,实际上,它并不返回承诺。在我们想要更新或调用一个函数的情况下,函数可以在setState函数中调用callback作为第二个参数。 例如,在上面的例子中,您调用了一个函数作为setState回调函数。

setState(
  { name: "Michael" },
  () => console.log(this.state)
);

上面的代码适用于类组件,但对于函数组件,我们不能使用setState方法,因此我们可以利用use effect钩子来实现相同的结果。

显而易见的方法是,你可以使用useEffect,如下所示:

const [state, setState] = useState({ name: "Michael" })

useEffect(() => {
  console.log(state) // do something after state has updated
}, [state])

但这也会在第一次呈现时触发,因此我们可以更改如下代码,检查第一次呈现事件并避免状态呈现。因此,可以通过以下方式实现:

我们可以在这里使用user钩子来标识第一次渲染。

useRef钩子允许我们在函数组件中创建可变变量。它对于访问DOM节点/React元素和存储可变变量而不触发重新渲染非常有用。

const [state, setState] = useState({ name: "Michael" });
const firstTimeRender = useRef(true);

useEffect(() => {
 if (!firstTimeRender.current) {
    console.log(state);
  }
}, [state])

useEffect(() => { 
  firstTimeRender.current = false 
}, [])

简单的解决方案,只需安装

我使用-state-with-callback

import React from 'react';
import { useStateWithCallbackLazy } from "use-state-with-callback";

const initialFilters = {
  smart_filter: "",
};

const MyCallBackComp = () => {
  const [filters, setFilters] = useStateWithCallbackLazy(initialFilters);

  const filterSearchHandle = (e) => {
    setFilters(
      {
        ...filters,
        smart_filter: e,
      },
      (value) => console.log("smartFilters:>", value)
    );
  };

  return (
    <Input
      type="text"
      onChange={(e) => filterSearchHandle(e.target.value)}
      name="filter"
      placeholder="Search any thing..."
    />
  );
};

认为: 反应usestate回调