我正在尝试下面的useEffect示例:

useEffect(async () => {
    try {
        const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`);
        const json = await response.json();
        setPosts(json.data.children.map(it => it.data));
    } catch (e) {
        console.error(e);
    }
}, []);

我在控制台得到这个警告。但我认为,对于异步调用,清理是可选的。我不知道为什么我得到这个警告。链接沙盒为例。https://codesandbox.io/s/24rj871r0p


当前回答

我通读了这个问题,觉得答案中没有提到实现useEffect的最佳方法。 假设您有一个网络呼叫,并且希望在得到响应后执行一些操作。 为了简单起见,让我们将网络响应存储在一个状态变量中。 人们可能希望使用action/reducer来更新存储与网络响应。

const [data, setData] = useState(null);

/* This would be called on initial page load */
useEffect(()=>{
    fetch(`https://www.reddit.com/r/${subreddit}.json`)
    .then(data => {
        setData(data);
    })
    .catch(err => {
        /* perform error handling if desired */
    });
}, [])

/* This would be called when store/state data is updated */
useEffect(()=>{
    if (data) {
        setPosts(data.children.map(it => {
            /* do what you want */
        }));
    }
}, [data]);

参考=> https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

其他回答

try

const MyFunctionnalComponent: React。FC = props => { useEffect(() => { //使用IIFE (async函数anyNameFunction() { 等待loadContent (); }) (); },[]); 返回< div > < / div >; };

这里可以使用Void运算符。 而不是:

React.useEffect(() => {
    async function fetchData() {
    }
    fetchData();
}, []);

or

React.useEffect(() => {
    (async function fetchData() {
    })()
}, []);

你可以这样写:

React.useEffect(() => {
    void async function fetchData() {
    }();
}, []);

它更干净,更漂亮。


异步效果可能会导致内存泄漏,因此在组件卸载时执行清理非常重要。在fetch的情况下,它可能是这样的:

function App() {
    const [ data, setData ] = React.useState([]);

    React.useEffect(() => {
        const abortController = new AbortController();
        void async function fetchData() {
            try {
                const url = 'https://jsonplaceholder.typicode.com/todos/1';
                const response = await fetch(url, { signal: abortController.signal });
                setData(await response.json());
            } catch (error) {
                console.log('error', error);
            }
        }();
        return () => {
            abortController.abort(); // cancel pending fetch request on component unmount
        };
    }, []);

    return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

最简单的方法是使用use-async-effect中的useAsyncEffect 你可以在NPM上找到它。

const ProtectedRoute = ({ children }) => {

    const [isAuth, setIsAuth] = useState(false);

    useAsyncEffect(async () => {
        try {
            const data = await axios("auth");
            console.log(data);
            setIsAuth(true);
        } catch (error) {
            console.log(error);
        }
    }, []);



    if (!isAuth)
        return <Navigate to="/signin" />

    return children;

}

使用自定义库提供的useAsyncEffect钩子,安全地执行异步代码并在效果中发出请求变得微不足道,因为它使您的代码可自动取消(这只是功能列表中的一件事)。查看带有JSON抓取的Live Demo

import React from "react";
import { useAsyncEffect } from "use-async-effect2";
import cpFetch from "cp-fetch";

/*
 Notice: the related network request will also be aborted
 Checkout your network console
 */

function TestComponent(props) {
  const [cancel, done, result, err] = useAsyncEffect(
    function* () {
      const response = yield cpFetch(props.url).timeout(props.timeout);
      return yield response.json();
    },
    { states: true, deps: [props.url] }
  );

  return (
    <div className="component">
      <div className="caption">useAsyncEffect demo:</div>
      <div>
        {done ? (err ? err.toString() : JSON.stringify(result)) : "loading..."}
      </div>
      <button className="btn btn-warning" onClick={cancel} disabled={done}>
        Cancel async effect
      </button>
    </div>
  );
}

export default TestComponent;

同样的演示使用了axios

对于其他读者,错误可能来自没有括号包装async函数的事实:

考虑异步函数initData

  async function initData() {
  }

这段代码将导致你的错误:

  useEffect(() => initData(), []);

但这一个,不会:

  useEffect(() => { initData(); }, []);

注意initData()周围的括号