嵌套对象值的 JSX 条件渲染

时间:2021-05-07 16:25:53

标签: javascript reactjs object jsx

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

代码:这里是我想要完成的,但是 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 中放置一个条件语句,以根据对象属性值为 true/false 来更改背景。

对象模型:

{
    "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]);
    });
});

1 个答案:

答案 0 :(得分: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)
}

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

为了使您的代码更简洁,而不是迭代对象的,而是迭代对象的。返回数组时也不需要片段 <></>

<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];
相关问题