如何通过 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;
【问题讨论】:
我看不到任何突出的东西。您映射了多少个配置文件?将Nav
和NavItem
移到条件之外可能会提高可读性,因为这两个组件总是被渲染。条件真的只是判断要渲染哪个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】:只是一个快速提示,您的条件渲染可以使用 &&
逻辑运算符,因为它不会在三元运算符的 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
不可用,它将呈现 &&
之后的项目或 null
【讨论】:
以上是关于如何通过 map 函数有条件地使用 React 和 Firebase 渲染元素?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 react-hook-form 有条件地禁用提交按钮?