在循环渲染下通过表达式自定义索引

Customize index by expression under loop rendering.

Posted by Reckless on October 9, 2023

浅析工作中遇到的组件循环渲染问题

需求背景

通过一个字符串数组中动态渲染 Dropdown 组件,句子 be like: ["一个", "keyword", "的", "keyword", "keyword"],渲染是需要将 keyword 替换为二次封装后的 DropdownBox 组件。看似很简单的一个需求,但遇到的问题就是 keyword 是有严格顺序的渲染,也就是说一个静态文件中读取 keyword 列表,按索引顺序(从 0 开始)排列渲染。

根据需求准确来说,在循环中,第一次页面渲染出 DropdownBox 时,传入这个组件的 index 必须为 0,第二次渲染出 DropdownBox 时传入的 index1

渲染方法的具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const Test = () => {
    const [arr, setArr] = useState(["一个", "keyword", "", "keyword", "keyword"])
    
    return(
        <div>
            {arr.map((item, index) => (
                    <div className="keywords" key={index}>
                        {item !== "keyword"
                            ?
                            <> {item}&nbsp; </>
                            :
                            <>
                                <DropdownBox keyword={getCurrentKeyword(index)}
                                             menu={keywordList[index]}
                                             getUserKeywordList={getUserKeywordList}
                                             keywordIndex={keywordIndex(index)}
                                />
                                {index !== moduleItem?.keywords.length - 1 && <>&nbsp;</>}
                            </>
                        }
                    </div>
            ))}
        </div>
    )
}

怎么将组件传入的属性 keywordIndexDropdownBox 组件本身进行强关联呢?

技术实现

1
2
3
4
5
6
7
8
// 在外部定义一个对象来存储关键字索引
// 在依赖项发生变化时自动进行数据重置
const keywordIndexes = useMemo(() => ({}), [moduleItem])

// 检查关键字是否已经存在于索引对象中,如果不存在则添加并赋值递增的索引
const keywordIndex = (index) => keywordIndexes[index] !== undefined
    ? keywordIndexes[index]
    : (keywordIndexes[index] = Object.keys(keywordIndexes).length)

因为赋值表达式的返回值是赋值的那个值(好像有点绕,简单解释 a = 1; 的返回值为 1),所以可以用这种方法来应对:
index 索引过大,导致读取 keywordIndexes 为 undefined,则给它赋值为这个对象的键的数量。如果可以读取得到,则使用它原本的键所对应的值

心得总结

JavaScript 的基础知识尤为重要,对象是很好处理复杂数据的办法,清楚 a = 1; 的返回值为 1 是解决问题的关键。



App ready for offline use.