如何通过 map 函数有条件地使用 React 和 Firebase 渲染元素?

Posted

技术标签:

【中文标题】如何通过 map 函数有条件地使用 React 和 Firebase 渲染元素?【英文标题】:How can I conditionally render elements with React and Firebase via map function? 【发布时间】:2018-08-27 06:18:59 【问题描述】:

我的主要目标是如果用户在 firebase 中没有个人资料,则有条件地呈现“创建个人资料”按钮,如果用户有个人资料,则有条件地呈现“编辑个人资料”按钮。

我在渲染编辑配置文件按钮时没有问题。我通过将身份验证用户“uid”与配置文件的“uid”进行比较来检查用户是否有配置文件。如果它们匹配,则将呈现编辑按钮。

我的问题是,当编辑按钮渲染时,创建按钮仍然出现,但它应该消失,因为我有条件地渲染这两个按钮。

我在这里错过了什么?

2018 年 3 月 23 日编辑

我已经找到了问题,但我仍然没有解决方案。问题是 map 函数正在循环遍历 'Profiles' 数组,并且正在寻找一个等于登录用户 'uid' 的 'uid'。

但如果 'uid' 与登录用户 'uid' 不匹配,创建按钮仍将呈现,因为 'Profiles' 数组中的其他配置文件的 uid 不等于登录用户 'uid .'

所以我想我的另一个问题是,

如何检查登录用户是否在数组和/或 Firebase 数据库中没有数据?

这是我的代码:

我有一个名为“配置文件”的数据库,我从中提取信息。

"Profiles" : 
"-L7p-wZNcvgBBTkvmn7I" : 
  "about" : "I'm a full stack web developer with many skills",
  "email" : "email@gmail.com",
  "frameworkOne" : "react",
  "frameworkThree" : "bootstrap",
  "frameworkTwo" : "javascript",
  "name" : "Dylan Prem",
  "projectInfo" : "You're on it!",
  "projectLink" : "https://hiremoredevs.com",
  "projectName" : "HireMoreDevs",
  "uid" : "ABCDEFG1234567"

反应组件:

class ProfileButtonToggle extends Component 
constructor(props)
    super(props);
    this.state = 
        authUser:null,
        Profiles:[]

    


componentDidMount()
  const profilesRef = firebase.database().ref('Profiles');
    profilesRef.once('value', (snapshot) => 
    let Profiles = snapshot.val();
    let newState = [];
    for (let profile in Profiles)
      newState.push(
        id: profile,
        uid:Profiles[profile].uid,
      );
    
    this.setState(
      Profiles: newState
    );
  );   

  firebase.auth().onAuthStateChanged((authUser) => 
      if (authUser) 
        this.setState( authUser );
       
    ); 



render() 
    return (
        <div>
        this.state.authUser ?
                <div>
                    this.state.Profiles.map((profile) => 
                        return(
                        <div key=profile.id>
                            profile.uid === this.state.authUser.uid ?
                            <Nav>
                                <NavItem>
                                    <Link className='btn yellow-button' to=`/edit/$profile.id`>Edit Profile</Link>
                                </NavItem>
                            </Nav>
                            :
                            <Nav>
                                <NavItem>
                                    <Link className='btn yellow-button' to=routes.CREATE_PROFILE>Create Profile</Link>
                                </NavItem>
                            </Nav>
                        
                        </div>
                    );
                    )
                </div>
            :
            null
        
        </div>

    );
  


export default ProfileButtonToggle;

【问题讨论】:

我看不到任何突出的东西。您映射了多少个配置文件?将NavNavItem 移到条件之外可能会提高可读性,因为这两个组件总是被渲染。条件真的只是判断要渲染哪个Link 你能告诉我们this.state.Profiles的内容是什么样的吗?看起来您正在迭代两次,一旦它通过了编辑按钮的条件,并且在下一次迭代中它仍然通过了创建按钮的条件。 看起来不错。也许为每个地图项添加一个 Id,以便您可以检查它是否真的在渲染两者。您正在映射一组用户,因此它可能会为一个用户显示“编辑”,而为另一个用户显示“创建”。 @brentatkins 我在 Profiles 数据库中有 2 个配置文件,都具有不同的 uid。我会试一试,然后告诉你结果如何。 @user3692823 我不想遍历它两次吗?检查 2 个条件。 【参考方案1】:

经过数周的拔毛,我终于找到了解决方案。事实证明,我什至不需要“创建”按钮。

componentDidUpdate 在渲染 DOM 后触发,这正是我所需要的。然后,我检查“Profiles”的子项的 uid 是否等于登录用户 uid,如果不是 push() 将当前用户 uid 发送到“Profiles”并重新加载页面。而且它确实奏效了!

换句话说,如果该用户不存在配置文件,它将自动创建一个配置文件。

componentDidUpdate() 
    firebase.database().ref("Profiles").orderByChild("uid").equalTo(this.state.authUser.uid).once("value",snapshot => 
        const userData = snapshot.val();
        if (userData)
          console.log("exists!");
         else 
            const profilesRef = firebase.database().ref('Profiles');
            const Profiles  = 
                uid: this.state.authUser.uid
            
            profilesRef.push(Profiles);
            window.location.reload();
        
    );

我将条件渲染更改为:

        <div>
        this.state.authUser ?
            <Nav>
                this.state.Profiles.map((profile) => 
                    return(
                    <NavItem key=profile.id>
                            profile.uid === this.state.authUser.uid ?
                                <Link id='edit-button' className='btn yellow-button job-text' to=`/edit/$profile.id`>Edit Profile</Link>
                                : 
                                null
                            
                    </NavItem>
                );
                )
            </Nav>
            :
            null
        
        </div>

页面重新加载后,编辑按钮按预期呈现。

完整的组件

class ProfileButtonToggle extends Component 
constructor(props)
    super(props);
    this.state = 
        authUser:null,
        Profiles:[],
    





componentDidMount()
    const profilesRef = firebase.database().ref('Profiles');
        profilesRef.once('value', (snapshot) =>        
            let Profiles = snapshot.val();
            let newState = [];
            for (let profile in Profiles)
              newState.push(
                id: profile,
                uid:Profiles[profile].uid,
              );

            
            this.setState(
              Profiles: newState
            );
          );

    firebase.auth().onAuthStateChanged((authUser) => 
      if (authUser) 
        this.setState( authUser );

        
         
    ); 


componentDidUpdate() 
    firebase.database().ref("Profiles").orderByChild("uid").equalTo(this.state.authUser.uid).once("value",snapshot => 
        const userData = snapshot.val();
        if (userData)
          console.log("exists!");
         else 
            const profilesRef = firebase.database().ref('Profiles');
            const Profiles  = 
                uid: this.state.authUser.uid
            
            profilesRef.push(Profiles);
            window.location.reload();
        
    );



render() 
    return (
        <div>
        this.state.authUser ?
            <Nav>
                this.state.Profiles.map((profile) => 
                    return(
                    <NavItem key=profile.id>
                            profile.uid === this.state.authUser.uid ?
                                <Link id='edit-button' className='btn yellow-button job-text' to=`/edit/$profile.id`>Edit Profile</Link>
                                : 
                                null
                            
                    </NavItem>
                );
                )
            </Nav>
            :
            null
        
        </div>
      );
    
 

 export default ProfileButtonToggle;

【讨论】:

【参考方案2】:

只是一个快速提示,您的条件渲染可以使用 &amp;&amp; 逻辑运算符,因为它不会在三元运算符的 else 部分返回任何内容

<div>
        this.state.authUser &&
            <Nav>
                this.state.Profiles.map((profile) => 
                    return(
                    <NavItem key=profile.id>
                            profile.uid === this.state.authUser.uid ?
                                <Link id='edit-button' className='btn yellow-button job-text' to=`/edit/$profile.id`>Edit Profile</Link>
                                : 
                                null
                            
                    </NavItem>
                );
                )
            </Nav>
        
        </div>

因此,如果 this.state.authUser 不可用,它将呈现 &amp;&amp; 之后的项目或 null

【讨论】:

以上是关于如何通过 map 函数有条件地使用 React 和 Firebase 渲染元素?的主要内容,如果未能解决你的问题,请参考以下文章

React Native - 如何在地图函数中传递索引

使用 map 函数在 React 中传递道具

如何使用 react-hook-form 有条件地禁用提交按钮?

使用 Dart 有条件地返回 Map() 中的元素

在 React 中有条件地添加表 n+1 表行 (<tr>)

如何在 React JS 中有条件地应用 CSS 类