繁体   English   中英

在异步函数完成运行之前反应渲染

[英]React rendering before async function finishes running

下面的程序从 Firebase 数据库读取数据,然后通过 setState 将其存储到变量中。 在第一次渲染时,没有 {problem} 是未定义的,因此不能在代码中使用。 这意味着 React 只会渲染一个带有硬编码文本的页面。 一旦 setState 运行,组件就会重新渲染,程序会显示数据。 我唯一的问题是,当我将 {problem} 变量传递给子组件时,它返回以下错误(显示的 AdditionalInfo.jsx 中的最后一行出现错误)。

AdditionalInfo.jsx:45 Uncaught TypeError: Cannot read properties of undefined (reading 'map')

为什么程序只返回子组件的错​​误,我该如何解决这个问题?

问题.jsx

const [problem, setProblem] = useState({});


    useEffect(() => {
        const getProblem = async () => {
            const problemsRef = collection(db, "problems");
            const q = query(problemsRef, where("problemNumber", "==", parseInt(params.id)));
            const querySnapshot = await getDocs(q);
            setProblem({...querySnapshot.docs[0].data()});
        }
        getProblem();
    }, [params.id]);
.
.
.

   return (
        <Split
        gutterSize={10}
        gutterAlign="center"
        cursor="col-resize"
        snapOffset={75}
        className='split'
        minSize={0}>
            <div className="bg-gray-100 min-h-screen max-h-screen overflow-y-auto"> {/* min-h-screen causes there to be a small scroll because of the navbar. To fix this use someting like min-h-screen minus height of navbar */}
                <div className='mx-2 my-2 text-1xl font-medium'>
                    {problem.problemNumber}. {problem.problemTitle}
                </div>
                <div className='mx-2 my-2 text-1xl font-normal text-green-600'>
                    {problem.problemType}
                </div>
                <Divider variant="middle" />
                <div className='mx-2 my-2 text-1xl text-base'>
                    {problem.problemQuestion}
                </div>

                <div>
                    {mapToArray(problem.companies).map(([key, value]) => {
                        return <CompanyTag key={key} companyName={value} companyId={key} />
                    }
                    )}
                </div>
                <AdditionalInfo problem={problem}/>
            </div>
                
            <div className="bg-gray-100">
                <div className='mx-7'>
                    <video width="100%" height="100%px" controls>
                        <source src="movie.mp4" type="video/mp4"></source>
                    </video>
                </div>
            </div>

        </Split>
    )   

附加信息.jsx

const AdditionalInfo = ({ problem }) => {

  return (
    <div>
        {problem.questionTips.map((tip) => {
            return <Tip key={tip.number} number={tip.number} description={tip.description} />
        })} // Code causes an error here
.
.
.

作为答案来回答。

错误是由于您最初设置const [problem, setProblem] = useState({}); 所以首先渲染你的问题只是一个空对象。 在您传递problem的子组件中,您尝试在 jsx 中使用 problem.questionTips.map() fn 并且由于第一次渲染问题。questionTips 未定义 - 尝试在未定义时访问 .map 会给您错误。

你应该使用? 运营商来解决这个问题。

{problem.questionTips?.map((tip) => {
  return <Tip key={tip.number} number={tip.number} description={tip.description} />
})}

回答评论中的其他问题:“有没有办法完全等到在渲染之前从 firebase 读取所有数据?”

是的,有一种方法,只需使用

{problem?.questionTips && <AdditionalInfo problem={problem}/>}

在加载questionTips problem ,这不会呈现您的 AdditionalInfo 组件

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM