在 useEffect 完成之前 React 钩子渲染组件

时间:2021-02-15 18:41:00

标签: reactjs axios react-hooks

我的 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。然后,它重新加载并显示带有结果的 <ul>。如何避免它首先显示“未找到数据”消息。

谢谢

4 个答案:

答案 0 :(得分:4)

最简单的调整是根据响应是否返回有条件地呈现 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>;

答案 1 :(得分:2)

它按预期工作,阅读有关 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

答案 2 :(得分:1)

这就是 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;

答案 3 :(得分:-4)

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

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

CodeSandbox demo here