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

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

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

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


当前回答

你的问题很有道理。让我告诉您,useEffect在默认情况下运行一次,并在每次依赖数组更改之后运行一次。

请看下面的例子:

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

const App = () => {
  const [age, setAge] = useState(0);
  const [ageFlag, setAgeFlag] = useState(false);

  const updateAge = ()=>{
    setAgeFlag(false);
    setAge(age+1);
    setAgeFlag(true);
  };

  useEffect(() => {
    if(!ageFlag){
      console.log('effect called without change - by default');
    }
    else{
      console.log('effect called with change ');
    }
  }, [ageFlag,age]);

  return (
    <form>
      <h2>hooks demo effect.....</h2>
      {age}
      <button onClick={updateAge}>Text</button>
    </form>
  );
}

export default App;

如果你想要setState回调与钩子一起执行,那么使用标志变量并在useEffect中给出If ELSE OR If块,以便当条件满足时,只执行该代码块。无论如何,当依赖项数组改变时,效果会运行,但效果中的IF代码只会在特定的条件下执行。

其他回答

我写了自定义挂钩与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])

我认为你需要的是useState和useCallback:

useState react doc; useCallback react doc;

示例代码

import React, { useCallback, useState } from 'react';

const Test = () => {
  const [name, setName] = useState("");
  const testCallback = useCallback(() => console.log(name), [name]);

  return (
    <button onClick={() => {
      setName("Michael")
      testCallback();
    }}>Name</button>
  )
};

export default Test;

我们可以写一个叫做useScheduleNextRenderCallback的钩子,它返回一个“schedule”函数。在我们调用setState之后,我们可以调用“schedule”函数,传递一个我们希望在下次呈现时运行的回调。

import { useCallback, useEffect, useRef } from "react";

type ScheduledCallback = () => void;
export const useScheduleNextRenderCallback = () => {
  const ref = useRef<ScheduledCallback>();

  useEffect(() => {
    if (ref.current !== undefined) {
      ref.current();
      ref.current = undefined;
    }
  });

  const schedule = useCallback((fn: ScheduledCallback) => {
    ref.current = fn;
  }, []);

  return schedule;
};

使用示例:

const App = () => {
  const scheduleNextRenderCallback = useScheduleNextRenderCallback();

  const [state, setState] = useState(0);

  const onClick = useCallback(() => {
    setState(state => state + 1);
    scheduleNextRenderCallback(() => {
      console.log("next render");
    });
  }, []);

  return <button onClick={onClick}>click me to update state</button>;
};

简化的测试用例:https://stackblitz.com/edit/react-ts-rjd9jk

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

我使用-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回调