首页  >  问答  >  正文

探讨React自定义组件中的条件渲染挑战

<p>我在我的React应用程序中的自定义组件中遇到了条件渲染的问题。我一直在努力创建一个用于条件渲染的自定义组件,只有在满足特定条件时才渲染内容。以下是我目前的代码:</p> <pre class="brush:js;toolbar:false;">import React from 'react'; function ConditionalRenderComponent({ condition, children }) { return ( <div> {condition && children} </div> ); } export default ConditionalRenderComponent; </pre> <p>在使用这个自定义组件时,我注意到通过<code>children</code>属性传递的内容即使<code>condition</code>为<code>false</code>时也被访问和执行。这与直接使用<code>condition && <div></div></code>而没有自定义组件的行为不同,后者在条件为<code>false</code>时正确地阻止了内容的访问。</p> <p><strong>以下是我使用自定义组件的方式:</strong></p> <pre class="brush:js;toolbar:false;">import React, { useState, useEffect } from 'react'; import ConditionalRenderComponent from './ConditionalRenderComponent'; function App() { const [userData, setUserData] = useState(null); const isLoggedIn = userData !== null; useEffect(() => { setTimeout(() => { setUserData({ username: 'john_doe', email: 'john@example.com' }); }, 1000); }, []); return ( <div> <h1>欢迎来到我的应用</h1> <ConditionalRenderComponent condition={isLoggedIn}> <div> <p>你好,{userData.username}!</p> <p>你的邮箱:{userData.email}</p> </div> </ConditionalRenderComponent> {!isLoggedIn && <p>请登录以访问用户数据。</p>} </div> ); } export default App; </pre> <p>在上面的示例中,<code>userData</code>最初为<code>null</code>,稍后通过从服务器检索到的数据进行填充。<code>isLoggedIn</code>条件取决于<code>userData</code>是否填充。</p> <p>然而,即使<code>isLoggedIn</code>条件为<code>false</code>(在获取数据之前),<code>ConditionalRenderComponent</code>内部的内容仍然尝试访问和显示<code>userData</code>。这导致错误消息:“TypeError: Cannot read properties of null (reading 'username')”。</p> <p><strong>与标准条件渲染的比较:</strong></p> <p>以下是使用标准的<code>condition && <div></div></code>方法的行为比较:</p> <pre class="brush:js;toolbar:false;">// 标准条件渲染 {isLoggedIn && ( <div> <p>你好,{userData.username}!</p> <p>你的邮箱:{userData.email}</p> </div> )} </pre> <p>如上面的代码所示,使用标准方法可以在条件为<code>false</code>时正确地阻止访问<code>userData</code>的值。</p> <p>我不确定为什么在使用带有<code>children</code>属性的自定义组件时会出现这种行为差异。我已经尝试过调试和寻找解决方案,但我还没有找到明确的答案。</p> <p>非常感谢您提供的任何见解或建议,以解释可能发生的原因以及如何修改自定义组件以实现对<code>children</code>属性的预期条件渲染行为。</p> <p>提前感谢您的帮助!</p>
P粉301523298P粉301523298451 天前558

全部回复(2)我来回复

  • P粉533898694

    P粉5338986942023-08-19 15:04:37

    为什么会发生这种情况?

    所以我认为发生这种情况的原因是,在ConditionalRenderComponent组件中,子元素被作为属性传递给它(就像函数的参数一样)。JSX表达式被作为函数的参数进行评估。

    这意味着即使condition为false,children在传递给ConditionalRenderComponent函数之前仍然会被评估。

    易于理解的示例

    你把一个PlayStation(在你的左手)和数学试卷成绩(在你的右手)给了一个孩子,并说如果他/她的分数超过90/100,他/她就会得到PlayStation。

    由于孩子已经可以看到你左手中的PlayStation(将children作为JSX表达式传递),他/她在检查条件之前就已经开始使用了。

    现在,如果你握紧你的拳头,相当于将children作为函数传递,他/她在检查你右手中的条件是否为真之前无法评估左手中的内容。

    解决方案

    我们通过使用一个函数作为子元素来修改我们的自定义组件,而不是直接在组件中渲染children。这样,您可以确保只有在condition为真时才会评估children

    对ConditionalRenderComponent的更改

    function ConditionalRenderComponent({ condition, children }) {
      return (
        <div>
          {condition && children()}
        </div>
      );
    }

    对渲染ConditionalRenderComponent的更改

    <ConditionalRenderComponent condition={isLoggedIn}>
            {() => (
              <div>
                <p>你好,{userData.username}!</p>
                <p>你的电子邮件:{userData.email}</p>
              </div>
            )}
    </ConditionalRenderComponent>

    回复
    0
  • P粉543344381

    P粉5433443812023-08-19 13:02:01

    我不建议为条件渲染创建一个组件,但如果你想这样做,你可以使用渲染属性模式,这样只有在条件为真时才调用函数。这样可以防止表达式立即被评估。

    function If({ condition, render }) {
      if (!condition) return null;
    
      return render();
    }
    
    export default function App() {
      const [state, setState] = useState(null);
    
      useEffect(() => {
        wait(1000).then(() => {
          setState({ hello: "world" });
        });
      }, []);
    
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
    
          <If condition={Boolean(state)} render={() => <p>{state.hello}</p>} />
        </div>
      );
    }

    回复
    0
  • 取消回复