-2

I have below code in TypeScript in which i am trying to use useRef and assign the arrayLength

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

but it never gets populated with arrayLength and comes as

ListRef Object current: []

Whats's wrong in the code? Why it never takes array value?

4
  • DId my previous answer not work? const listRef = useMemo(() => messages.map(() => React.createRef<HTMLElement>()), []) - stackoverflow.com/questions/63451730/… Commented Aug 17, 2020 at 16:01
  • @SILENT, nope, its giving TypeError: Cannot read property 'current' of undefined Commented Aug 17, 2020 at 16:05
  • @SILENT getting error as expecting 0 argument but got 1`' Commented Aug 17, 2020 at 16:11
  • My bad. Not a Typescript expert. Commented Aug 17, 2020 at 16:12

1 Answer 1

1

From what you've told us, the only explanation is that message.length as of the first call to useRef is 0. Subsequent calls to useRef after that (e.g., when the component is re-rendered) will ignore the initial value you pass in, instead returning the ref created by the first call to useRef.

Here's a simple example showing that happening:

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>

If the goal is to expand/contract the array of refs to match message, you have to do that explicitly. I wouldn't use an array for it, I'd use a Map, keyed by some unique information about the entry in message that the ref will be used for. That way, the code isn't confused when things are inserted at the beginning of message, or in the middle, or when things are rearranged. That might look something like:

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());
    }
}

...and then using them:

{message.map(entry => <whatever ref={messageRefs.get(entry.id)}>...</whatever>)}
Sign up to request clarification or add additional context in comments.

2 Comments

@Lara - That depends on what you're trying to accomplish...?
@Lara - I've taken a swing at what I think you may be trying to do, but...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.