首页 > 解决方案 > useRef 未填充 arrayLength

问题描述

我在 TypeScript 中有以下代码,我试图在其中使用useRef和分配 arrayLength

const listRef = useRef(Array.from({ length: message.length }, a => React.createRef()));

但它永远不会填充 arrayLength 并作为

ListRef 对象当前:[]

代码有什么问题?为什么它从不采用数组值?

标签: javascriptreactjstypescriptreact-hooksuse-ref

解决方案


从您告诉我们的情况来看,唯一的解释是message.length第一次调用时useRef0. 之后的后续调用useRef(例如,重新渲染组件时)将忽略您传入的初始值,而是返回第一次调用创建的 ref useRef

这是一个简单的示例,显示了这种情况:

const { useRef, useState, useEffect } = React;

function Example({message}) {
    console.log(`Component rendered, message.length = ${message.length}`);
    const listRef = useRef(Array.from({ length: message.length }, a => React.createRef()));
    console.log(`Component rendered, listRef.current.length = ${listRef.current && listRef.current.length}`);
    
    return <div>x</div>;
}

function Parent() {
    const [message, setMessage] = useState<([]);
    useEffect(() => {
        setTimeout(() => {
            setMessage([1, 2, 3]);
        }, 800);
    }, []);
    
    return <Example message={message} />;
}

ReactDOM.render(<Parent/>, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>

如果目标是扩展/收缩 refs 数组以匹配message,则必须明确执行此操作。我不会为它使用数组,我会使用, 由有关将使用 refMap的条目的一些唯一信息键入。message这样,当在 的开头message或中间插入内容或重新排列内容时,代码不会混淆。这可能看起来像:

const {current: messageRefs} = useRef<Map<someType, React.RefObject<HTMLElement>>(new Map());
//                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                                                 \
//                                                  −− this part is TypeScript-
//                                                     specific; update the
//                                                     `someType` part to match
//                                                     the type of the unique
//                                                     information you're using,
//                                                     and the `HTMLElement` part
//                                                     to match the type of
//                                                     element you're storing in
//                                                     the ref
for (const {id} of message) {
    if (!messageRefs.get(id)) {
        messageRefs.set(id, React.createRef());
    }
}

...然后使用它们:

{message.map(entry => <whatever ref={messageRefs.get(entry.id)}>...</whatever>)}

推荐阅读