5

I'm struggling with passing refs between components in React. I've decided to use React.forwardRef but i occur a problem. Here is my code

const Wrapper = React.forwardRef((props, ref) => {
  return (
    <StyledWrapper ref={ref} >
      {console.log(ref.current)}
      <ParallaxProvider scrollContainer={ref.current}>
        <TransitionProvider value={ref.current}>{children}</TransitionProvider>
      </ParallaxProvider>
    </StyledWrapper>
  );
});

export default class MainTemplate extends React.Component {
  constructor(props) {
    super(props);
    this.scrollContainer = React.createRef();
  }


  render() {
    const { toggled, overflow } = this.state;
    const { uri, children } = this.props;
    return (
      <>
        <SEO />
        <GlobalStyle />
        <ThemeProvider theme={GlobalTheme}>
          <>
            <Hamburger handleToggle={this.handleToggle} />
            <Perspective active={toggled}>
              <Navigation pathname={uri} handleToggle={this.handleToggle} />
              <Wrapper
                ref={this.scrollContainer}
              >
                {children}
              </Wrapper>
            </Perspective>
          </>
        </ThemeProvider>
      </>
    );
  }
}

I need to pass ref.current to and but the problem is that ref.current is always null. Can anybody explain me this behavior and how can i make it works?

hans001
  • 123
  • 1
  • 2
  • 8
  • log the `ref` after the component mounts, you can place the `console.log(ref)` inside the component body or inside `useEffect`. you can't log the ref before the dom has been updated – Asaf Aviv Dec 29 '19 at 19:22
  • React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts. ref updates happen before componentDidMount or componentDidUpdate lifecycle methods. – Gaurav verma Dec 29 '19 at 19:24

1 Answers1

7

In React refs are always assigned after the first render. Trying to access before the first render will give a null object.

One way to get around this is to use conditional rendering

const Wrapper = React.forwardRef((props, ref) => {
    return (
        <StyledWrapper ref={ref} >
            {ref.current && 
                <ParallaxProvider scrollContainer={ref.current}>
                    <TransitionProvider value={ref.current}>{children}</TransitionProvider>
                </ParallaxProvider>
            }
        </StyledWrapper>
    );
});

Also if you wrote the ParallaxProvider and TransitionProvider components, you can modify them to only use scrollContainer and value respectively when they're not null...

It's worth pointing out that React doesn't rerender on ref change but since this is being passed as a prop to Wrapper, a change in the prop will cause a rerender and you should be able to get ref.current.

Kwame Opare Asiedu
  • 2,110
  • 11
  • 13