【问题标题】:How to set/access data object correctly using React with a Firebase database?如何使用带有 Firebase 数据库的 React 正确设置/访问数据对象?
【发布时间】:2022-01-08 15:20:15
【问题描述】:

在从 Firebase 数据库检索数据后,我在 React 中使用 useState 挂钩存储和访问数据时遇到问题。问题似乎源于并非所有用户都拥有playerData数据包中的所有值——在这种情况下,如果玩家有“先锋”成就,他们可以创建一个解决方案,如果没有,他们只能设置他们的个人资料名称(然后在playerData 中有一个未定义的settlementName)。如果帐户有所有相关数据,它工作正常,但如果没有,那么它会遇到一堆空值的 TypeErrors。

谁能告诉我我在这里做错了什么?我想知道我是否应该使用NoPioneer()(如果用户被确定为没有先驱成就时执行)将空值填充到playerData 对象中,这样它至少不会命中对象中的空引用。

此外,我发现如果我删除了组件渲染的playerData.settlement.settlementName 渲染引用(根据玩家的先驱状态可能存在或不存在的数据)。所以,这让我觉得我可能需要在渲染调用中添加一个条件来检查数据是否存在(但遗憾的是我不确定如何执行此操作)。

这是我的 React 组件供参考:

function Dashboard() {
    const [ error, setError ] = useState('');
    const history = useHistory();

    const pioneer_emails = Firebase.database().ref("pioneer_emails");
    const player_achievements = Firebase.database().ref("players/" + currentUser.uid + "/achievements");
    const [ pioneer, setPioneer ] = useState(false);
    const [ playerData, setPlayerData ] = useState({
        player_data: {
            playerName: "",
        },
        settlement: {
            settlementName: "",
        }
    });
    const playerName = playerData.player_data.playerName;
    const settlementName = playerData.settlement.settlementName;

    var dateVariable = Date().toLocaleString()

    async function CheckForPioneer(){
        //check if email is on pioneer list
        await pioneer_emails.on('value', gotEmail, errData);
        //if not, then check if the player has the achievement already
        if(!pioneer) {
            player_achievements.on('value', gotAchievement, noPioneer);
        }
    }

    //check to see if the player's email is on the pioneer list
    function gotEmail(data){
        //console.log(data.val())
        var emails = data.val();
        var keys = Object.keys(emails);

        for(var i = 0; i < keys.length; i++){
            let k = keys[i];
            if(emails[k] === currentUser.email){
                //set bool
                setPioneer(true);
                //add achievement to database
                SetPioneerAchievement();
                //delete email from database
                pioneer_emails.child(k).remove();
            }
        }
    }

    //check to see if the player has the pioneer achievement
    function gotAchievement(data){
        var achievements = data.val();
        var achievementKeys = Object.keys(achievements);

        for(var i = 0; i < achievementKeys.length; i++){
            if(achievementKeys[i] === "MISC001"){
                setPioneer(true);
                console.log("We got a pioneer, baby!");
            }
        }
    }

    function noPioneer(){
        console.log('Player is not a pioneer!');
    }

    function errData(err){
        console.log('Error!');
        console.log(err)
    }

    function GetPlayerData(){
        Firebase.database().ref().child("players").child(currentUser.uid).get().then((snapshot) => {
        if (snapshot.exists()) {
            setPlayerData(snapshot.val());
            console.log(snapshot.val());
            console.log(playerData);
            console.log(playerData.player_data.playerName);         
            console.log(playerData.settlement.settlementName);
        } else {
            console.log("No data available");
        }
        }).catch((error) => {
        console.error(error);
        });
    }

    function SetPioneerAchievement(){
        const achievement = {
            "MISC001": {
                name: "Kickstarter Pioneer",
                completed: dateVariable
            }
        }
        player_achievements.set(achievement).catch(alert);
        console.log('Achievement added: ' + achievement.name)
    }

    useEffect(() => {
        GetPlayerData();
        CheckForPioneer();
    }, []);

    return (
    <div className="dashboard">
        <div className="dashboard-box">
            <div className="dashboard-content">
                <h1>DASHBOARD</h1>
                <br /><alert>{error}</alert>
                <br />
                <center><h3>Name:</h3></center>
                <center><h2>Ancestor {playerData && playerData.player_data.playerName}</h2></center>
                <center>{pioneer ? <h3 className="pioneer-tag">Pioneer from the 2021 Kickstarter Campaign</h3> : null }</center>
                <br /><br />
                { pioneer ? (
                <div><center><h3>Founder of the:</h3></center>
                <center><h2>{playerData && playerData.settlement.settlementName} Settlement</h2></center></div>
                )
                : null }
                <center><Link to="/update-dashboard" className="link"><input type="submit" id="ancestor-signup-submit"  name="dashboard-update-details" value="Update Details" /></Link></center>
                <br />
                <div class="footer-switch-login">
                    <center><Link to="/" onClick={handleLogout} className="link">Log out.</Link></center>
                </div>

            </div>
        </div>
    </div>
  );
}

export default Dashboard;

任何帮助将不胜感激,因为我不知所措。谢谢!

【问题讨论】:

    标签: javascript reactjs firebase firebase-realtime-database use-state


    【解决方案1】:

    因此,如果我正确理解您的问题/问题,则代码基本上可以按预期工作,但有时某些用户/数据/状态不完整。为此,解决方案是使用 null-checks/guard-clauses 或 Optional Chaining operator

    排序已经在几个地方这样做了:

    playerData && playerData.player_data.playerName
    

    playerData && playerData.settlement.settlementName
    

    但您并未检查对象属性访问的每个深度。

    1. 使用空检查/保护子句。

       playerData &&
       playerData.player_data &&
       playerData.player_data.playerName
      

       playerData &&
       playerData.settlement &&
       playerData.settlement.settlementName
      
    2. 使用可选链接运算符

       playerData?.player_data?.playerName
      

       playerData?.settlement?.settlementName
      

    我想知道我是否应该使用NoPioneer()(如果用户 被认定为无开创性成果)填空 playerData 对象的值,以便它至少不会命中 null 对象中的引用。

    这听起来像是一个绝妙的主意,因为它有助于消除潜在访问 null 或未定义对象属性的机会。

    【讨论】:

    • 嗨,德鲁,感谢您在这方面的帮助!我将选项 1 与空检查一起使用,效果很好。也非常感谢细节,因为它帮助我理解了实际​​发生的事情。祝你这份善意+1000祝福!祝你好运。
    猜你喜欢
    • 2020-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多