primefaces / primefaces/primereact

ForwardedRef-Components: ref cannot be accessed on useLayoutEffect lifecycle

Open
#8,391 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Type: Enhancement
Dominant language
CSS
Stars
8.3k
Forks
1.2k
PR merge metrics
No merged PRs in 30d

Description

Describe the bug

A given ref to component can not be accessed in useLayoutEffect. The problem exists in Button and InputText, I think other components may also be affected, maybe only those which do not use useImperativeHandle.

function MyButton(){
  const ref = useRef(null);
  useLayoutEffect(() => ref.current.focus());
  return <Button ref={ref}>Click</Button>
}

Error: ref.focus is null

Here are some parts from sourcecode of Button:

export const Button = React.forwardRef((inProps, ref) => {
        const elementRef = React.useRef(ref);

        React.useEffect(() => {
            ObjectUtils.combinedRefs(elementRef, ref);
        }, [elementRef, ref]);

        const rootProps = mergeProps(
            {
                ref: elementRef,
               (...)
            },
            (...)
        );

        return (
            <>
                <button {...rootProps}>
                    (...)
                </button>
            </>
        );
}

useEffect will synchronize both ref. Therefore useLayoutEffect which runs earlier can not access the forwardedRef.

I do not understand why ref should be initValue for elementRef.
const elementRef = React.useRef(ref);

Possible solution with custom hook:

function useForwardedRef(forwardedRef){
  const ref= React.useRef();
  if(forwardedRef) return forwardedRef;
  return ref;
}

export const Button = React.forwardRef((inProps, ref) => {
        const elementRef = useForwardedRef(ref);
        return (
            <>
                <input ref={elementRef} {...rootProps} />
                (...)
            </>
}

Maybe Utils.combinedRef will be obsolete.

Reproducer

No response

System Information
react 18.2
primereact 10.5.1
Steps to reproduce the behavior

No response

Expected behavior

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Inspect the forwarded-ref implementations in Button and InputText, including ObjectUtils.combinedRefs and the elementRef initialization shown in the issue. Reproduce the case with a parent useLayoutEffect, then add or update a regression test; done means the forwarded ref is available when that effect runs.

Written by the indexing model from the issue text.

Assessment

Tech stack
react
Domain
frontend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.