Forward Ref giving value of current as null

797 Views Asked by At

I am trying to implement forward Ref in my Demo Project but I am facing one issue. The value of current coming from forward ref is null, but once I re-render my NavBar component (by sending a prop) I get the value of current.

I basically need to scroll down to my Section present in Home Component from NavBar Component. It can be done by directly by giving a href attribute and passing the id. But I wanted to learn how forward ref works and hence this approach.

Can someone please help me with this?

Here is my Code.

import './App.css';
import NavBar from './components/NavBar/NavBar';
import Home from './components/Home/Home';

class App extends Component {

  constructor(props) {
    super(props);
    this.homeRefService = React.createRef();
    this.homeRefContact = React.createRef();
  }

  render() {
    return (
      <div className="App">
        <NavBar name={this.state.name} homeRef={{homeRefService: this.homeRefService , homeRefContact: this.homeRefContact}}/>
        <Home ref={{homeRefService: this.homeRefService, homeRefContact: this.homeRefContact }}/>
      </div>
    );
  }
    
}

export default App;



**Home Component**
import React from 'react';

const home = React.forwardRef((props , ref) => {
    const { homeRefService , homeRefContact  } = ref;

    console.log(ref);
  
    return (
        <div>
            <section ref={homeRefService} id="Services">
                Our Services
            </section>

            <section ref={homeRefContact} id="Contact">
                Contact Us
            </section>
        </div>
    )
})

export default home


**NavBar Component**

import React, { Component } from 'react'

export class NavBar extends Component {


    render() {

        let homeRefs =  this.props.homeRef;

        let homeRefServiceId;
        let homeRefContactId;

        if(homeRefs.homeRefService.current) {
            homeRefServiceId = homeRefs.homeRefService.current.id;
        }
        if(homeRefs.homeRefContact.current ) {
            homeRefContactId = homeRefs.homeRefContact.current.id;
        }
        
        return (
            <div>
                <a  href={'#' + homeRefServiceId}> Our Services</a> 
                <a  href={'#' + homeRefContactId }>Contact Us</a>
            </div>
        )
    }
}

export default NavBar
2

There are 2 best solutions below

0
On BEST ANSWER

The ref is only accessible when the component got mounted to the DOM. So you might want to access the DOM element in componentDidMount.I suggest you to lift the state up to the parent component.
Demo

// App
class App extends React.Component {
  constructor(props) {
    super(props);
    this.homeRefService = React.createRef();
    this.homeRefContact = React.createRef();
    this.state = { homeServiceId: "", homeContactId: "" };
  }

  componentDidMount() {
    this.setState({
      homeServiceId: this.homeRefService.current.id,
      homeContactId: this.homeRefContact.current.id
    });
  }

  render() {
    return (
      <div className="App">
        <NavBar
          homeServiceId={this.state.homeServiceId}
          homeContactId={this.state.homeContactId}
        />
        <Home
          ref={{
            homeRefService: this.homeRefService,
            homeRefContact: this.homeRefContact
          }}
        />
      </div>
    );
  }
}

// NavBar    
export class NavBar extends Component {
  render() {
    return (
      <div>
        <a href={"#" + this.props.homeServiceId}> Our Services</a>
        <a href={"#" + this.props.homeContactId}>Contact Us</a>
      </div>
    );
  }
}

export default NavBar;
0
On

All your code just be oke. You can access ref after all rendered.

Example demo how do it work:

export class NavBar extends Component {


    render() {

        let homeRefs =  this.props.homeRef;

        console.log('from Nav Bar');
        console.log(this.props.homeRef.homeRefService);
        console.log('----');

        let homeRefServiceId;
        let homeRefContactId;

        if(homeRefs.homeRefService.current) {
            homeRefServiceId = homeRefs.homeRefService.current.id;
        }
        if(homeRefs.homeRefContact.current ) {
            homeRefContactId = homeRefs.homeRefContact.current.id;
        }

        return (
            <div>
                <a  href={'#' + homeRefServiceId}> Our Services</a>
                <a  href={'#' + homeRefContactId }>Contact Us</a>
            </div>
        )
    }
}

const Home = React.forwardRef((props , ref) => {
    const { homeRefService , homeRefContact  } = ref;


    useEffect(() => {
        console.log('from home');
        console.log(homeRefService);
        console.log('----');

        props.showUpdate();
    })

    return (
        <div>
            <section ref={homeRefService} id="Services">
                Our Services
            </section>

            <section ref={homeRefContact} id="Contact">
                Contact Us
            </section>
        </div>
    )
})

class App extends Component {
    state = {
        name: 'init',
    }

    constructor(props) {
        super(props);
        this.homeRefService = React.createRef();
        this.homeRefContact = React.createRef();
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log('from app');
        console.log(this.homeRefService);
        console.log('----');
    }

    render() {
        return (
            <div className="App">
                <div>{this.state.name}</div>
                <NavBar name={this.state.name} homeRef={{homeRefService: this.homeRefService , homeRefContact: this.homeRefContact}}/>
                <Home showUpdate={() => this.state.name === 'init' && setTimeout(() => this.setState({name: 'UpdatedRef'}), 2000)} ref={{homeRefService: this.homeRefService, homeRefContact: this.homeRefContact }}/>
            </div>
        );
    }
}