【问题标题】:React hooks rendering component before useEffect finishes在 useEffect 完成之前 React 钩子渲染组件
【发布时间】:2021-05-18 16:02:38
【问题描述】:

我的 useEffect 中有一个异步请求。我注意到该组件是在 useEffect 完成之前呈现的。

import React, { useEffect } from 'react';
import axios from 'axios';

import './SearchWords.css';

const URL_REQUEST = 'http://myLink.com';

const SearchWords = (props) => {
    const { setState } = props;

    useEffect(async () => {
        const data = {
            sentence: props.sentence
        };
      
        await axios.post(`${URL_REQUEST}/getData`, { data })
            .then((res) => {
                setState(state =>({
                    ...state,
                    search: res.data
                }));
            })
            .catch((err) =>{
                console.log(err);
            })
    }, []);

    const render = () => {
        if(props.search.length > 0) {
            const linkMarkup = props.search.map((link) => (
                <li key={link.id} className="link-list-item">
                  <a
                    href={link.link}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="link-list-item-url"
                    onClick
                  >
                    {link.name}
                  </a>
                </li>
            ));
            
            return <ul className="link-list">{linkMarkup}</ul>;
        } else {
            return <p>No data found for: {props.sentence}</p>
        }
    }

    return render()
}

export default SearchWords;

它正在工作,但它首先显示No data found for: My Search String。然后,它重新加载并显示&lt;ul&gt; 和结果。如何避免首先显示“未找到数据”消息。

谢谢

【问题讨论】:

  • 跟踪请求何时通过状态加载。如果请求仍在加载,您可以显示微调器。一旦你得到数据,你就可以显示它。如果没有返回数据,您可以显示“未找到数据”消息。通常,您不希望在发出异步请求时阻止 UI 呈现。加载微调器可以更好地指示最终用户您的应用正在尝试在后台加载数据。

标签: reactjs axios react-hooks


【解决方案1】:

最简单的调整是根据响应是否返回,有条件地渲染 JSX 的该部分:

const [hasLoaded, setHasLoaded] = useState();
// ...
.then((res) => {
    setState(state =>({
        ...state,
        search: res.data
    }));
    setHasLoaded(true);
})

然后改变

return <p>No data found for: {props.sentence}</p>

return hasLoaded ? <p>No data found for: {props.sentence}</p> : <p>Loading...</p>;

【讨论】:

  • 还应该提到,如果 HTTP 响应出现乱序,他们的组件中目前没有做任何事情来防止旧响应覆盖新响应。
  • 太棒了!谢谢。
【解决方案2】:

您想在屏幕上呈现任何内容之前跟踪您的 fetch 调用是否已解决。

您可以使用React.useRef 来跟踪此状态。

CodeSandbox demo here

【讨论】:

  • 这绝对不是采取的方法
  • 现在想想,React.useState 还可以存储“我的 api 调用是否完成加载”的状态。 @23k 这是您考虑的方法吗?
【解决方案3】:

useEffect 就是这样工作的:它会安排一个副作用在组件渲染后运行。

来自the docs

useEffect 有什么作用?通过使用这个 Hook,你告诉 React 你的组件需要在渲染之后做一些事情。 React 会记住您传递的函数(我们将其称为“效果”),并在执行 DOM 更新后稍后调用它。在这个效果中,我们设置了文档标题,但我们也可以执行数据获取或调用其他一些命令式 API。

您可以做的是跟踪效果状态以显示加载指示器,直到完成。

import React, { useEffect } from 'react';
import axios from 'axios';

import './SearchWords.css';

const URL_REQUEST = 'http://myLink.com';

const SearchWords = (props) => {
    const { setState } = props;
    const [isLoading, setLoading] = React.useState(true);

    useEffect(async () => {
        const data = {
            sentence: props.sentence
        };
      
        await axios.post(`${URL_REQUEST}/getData`, { data })
            .then((res) => {
                setState(state =>({
                    ...state,
                    search: res.data
                }));
                setLoading(false);
            })
            .catch((err) =>{
                console.log(err);
            })
    }, []);

    const render = () => {
        if(isLoading) return "Loading...";

        if(props.search.length > 0) {
            const linkMarkup = props.search.map((link) => (
                <li key={link.id} className="link-list-item">
                  <a
                    href={link.link}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="link-list-item-url"
                    onClick
                  >
                    {link.name}
                  </a>
                </li>
            ));
            
            return <ul className="link-list">{linkMarkup}</ul>;
        } else {
            return <p>No data found for: {props.sentence}</p>
        }
    }

    return render()
}

export default SearchWords;

【讨论】:

    【解决方案4】:

    它正在按预期工作阅读有关react lifecycle 的更多信息。要在您使用功能组件时处理这种情况,请使用 useState() 钩子获取 API 状态。

    const [isLoading, setIsLoading] = useState(true);
    useEffect(() => {
     // api call
     // now after api call set setIsLoading(false);
    },[]}
    
    if(isLoading) {
      // return show loading spinner
    }
    
    // else remaining code
    

    【讨论】:

      猜你喜欢
      • 2021-06-24
      • 2021-08-25
      • 2021-11-21
      • 2021-04-17
      • 2021-01-06
      • 2018-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多