【问题标题】:JSX Conditional Rendering for Nested Object Values嵌套对象值的 JSX 条件渲染
【发布时间】:2021-05-07 16:25:53
【问题描述】:

我试图让“抽认卡”在未回答时不显示背景颜色,正确回答时显示绿色,错误回答时显示黄色。每张卡片的属性都存储在一个嵌套对象中。我在使用条件渲染来正确显示我的内容时遇到问题。

代码:这是我想要完成的,但是 JSX 条件语句只注册了 className 中的最后一条语句。

<div className="row">
    {Object.keys(this.state.selections).map( (lang, index) => (
        <>
            {Object.keys(this.state.selections[lang]).map( (cat, index) => (
                <>
                {Object.keys(this.state.selections[lang][cat]).map( (sect, index)=> (
                    <>
                    {Object.keys(this.state.selections[lang][cat][sect]).map( (letter, index)=> (
                        <>
                        {this.state.selections[lang][cat][sect][letter].show &&
                            <div className={
                                (this.state.selections[lang][cat][sect][letter].correct ? correct: unanswered),
                                (this.state.selections[lang][cat][sect][letter].incorrect ? incorrect : unanswered)
                            } key= {index}>
                            </div>
                        }
                        </>
                    ))}
                    </>
                ))}
                </>
            ))}
        </>
    ))}
</div>

基本上,我想在 className 中放置一个条件语句,以根据对象属性值为真/假来更改背景。

对象模型:

{
    "Hiragana": {
        "Main Kana": {
            "Vowels": {
                "a": {
                    "characterName":  "A",
                    "character":  "あ",
                    "unicode":  "\u0026‌#12354;",
                    "hexEncoding":  "\u0026‌#x3042",
                    "englishTranslation":  "a",
                    "alternateEnglishTranslation":  "",
                    "isLetter":  "1",
                    "alphabet":  "hir",
                    "show": false,
                    "answer": "",
                    "correct": false,
                    "incorrect": false,
                    "unanswered": true
                    },

额外问题:必须循环遍历每个对象层似乎有点混乱和乏味......有什么好方法可以缩短它吗? langcat 是通过输入选择的,因此它们不能被硬编码。虽然我目前的解决方案“有效”,但我想尽可能提高自己。

更新:来自@CertainPerformance 提供的解决方案的工作代码

<div className="row">
    {Object.keys(this.state.selections).map(lang => 
        Object.values(this.state.selections).map( (cat) =>
            Object.values(cat).map((sect, indexCat) =>
                Object.values(sect).map((sectLetters, indexSect) =>
                    Object.values(sectLetters).map((letter, indexSectL) =>
                        letter.show &&
                        <div
                            className={getBgClass(letter)}
                            key={indexSectL}>
                            <div>
                                <h5 className="card-title" >{letter.character}</h5>
                                <input data-lang={lang} data-cat={Object.getOwnPropertyNames(cat)[indexCat]} data-sect={Object.getOwnPropertyNames(sect)[indexSect]} type="text" name={letter.characterName} value={letter.answer} onChange={this.handleChange.bind(this)} />
                            </div>
                        </div>
                    )
                )
            )
        )
    )}
</div>

对于那些对我对访问由 Object.values 生成的数组的解释感到困惑的人,这里有一个简单的 console.log 示例来更好地解释。

Object.values(this.state.selections).map((cat) =>{
    Object.values(cat).map((sect, indexCat) => {
        console.log("Cat: ", Object.getOwnPropertyNames(cat)[indexCat]);
    });
});

【问题讨论】:

    标签: javascript reactjs object jsx


    【解决方案1】:

    我不确定您当前的代码是否按预期工作。这里:

    className={
      (this.state.selections[lang][cat][sect][letter].correct ? correct : unanswered),
      (this.state.selections[lang][cat][sect][letter].incorrect ? incorrect : unanswered)
    }
    

    您正在调用逗号运算符,它仅计算逗号分隔列表中的最终表达式。相当于:

    className={
      (this.state.selections[lang][cat][sect][letter].incorrect ? incorrect : unanswered)
    }
    

    要修复它,要么使用嵌套条件运算符,要么将其传递给函数。

    为了让你的代码更简洁,不要迭代对象的keys,而是迭代对象的values。返回数组时,您也不需要片段&lt;&gt;&lt;/&gt;

    <div className="row">
        {Object.values(this.state.selections).map(selection =>
            Object.values(selection).map(cat =>
                Object.values(cat).map(sect =>
                    Object.values(sect).map((letter, index) =>
                        letter.show &&
                        <div
                            className={
                                letter.correct
                                    ? correct
                                    : letter.incorrect
                                        ? incorrect
                                        :
                                        unanswered
                            }
                            key={index}
                        >
                        </div>
                    )
                )
            )
        )}
    </div>
    

    为避免嵌套条件,如果这是您的偏好,请执行以下操作:

    <div
        className={getClass(letter)}
        key={index}
    ></div>
    
    const getClass = (letter) => {
      if (letter.correct) return correct;
      if (letter.incorrect) return incorrect;
      return unanswered;
    };
    

    您还可以考虑更改模型,以便问题状态(正确/不正确/未回答)是单个属性,而不是多个属性,例如,而不是

    "correct": false,
    "incorrect": false,
    "unanswered": true
    

    answerState: 2
    

    其中 2 对应于未回答,1 对应于不正确,0 对应于正确 - 或类似的东西。然后你可以使用一个数组来查找合适的类名:

    className={classNames[letter.answerState]}
    
    const classNames = [correct, incorrect, unanswered];
    

    【讨论】:

    • 你是一个有福的人。这是我需要的一切,还有更多。我想我现在要保留这三个属性,以便更好地可视化它。还弄清楚如何钻入 Object.values 非常有趣......似乎为了让您访问它生成的数组,您必须下一个 .map 函数并使用嵌套的索引来循环遍历父...非常奇怪且难以解释,但我会用最终结果更新我的问题!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 2021-02-01
    • 2016-10-29
    • 2020-10-12
    • 2018-10-16
    • 2021-10-11
    • 2020-06-05
    相关资源
    最近更新 更多