2

Here is my react hooks code:

function Simple(){
    var [st,set_st]=React.useState(0)
    var el=React.useRef(null)
    if (st<1)
        set_st(st+1)//to force an extra render for a grand total of 2
    console.log('el.current',el.current,'st',st)
    return <div ref={el}>simple</div>
}
ReactDOM.render(<Simple />,document.querySelector('#root') );

I thought it should render twice. the first time el.current should be null and second time is should point to the DOM object of the div. when running this, this was the output

el.current null st 0
el.current null st 1

It did, yes, render twice. however, the second render th el.current is still null. why?

solution: as described by Gireesh Kudipudi below. I added useEffect

function Simple(){
    var [st,set_st]=React.useState(0)
    var el=React.useRef(null)
    if (st<1)
        set_st(st+1)//to force an extra render for a grand total of 2
    console.log('el.current',el.current,'st',st)
    React.useEffect(_=>console.log('el.current',el.current,'st',st)) //this prints out the el.current correctly
    return <div ref={el}>simple</div>
}
ReactDOM.render(<Simple />,document.querySelector('#root') );

2 Answers 2

5

It could be that you are fixated on amount of renderings which is not necessarily the best React mindset when working with hooks. Mindset should be more like what has changed in my world.

From that point, try adding a useEffect and tell it you're interested in seeing when ref changes within my world. Try the following example, and see the behavior yourself.

let renderCounter = 0;

function Simple() {
  const [state, setState] = useState()
  const ref = React.useRef(null)

  if (state < 1) {
    /** 
     * We know this alter the state, so a re-render will happen
     */
    setState('foo')
  }

  useEffect(() => {
    /**
     * We don't know exactly when is `ref.current` going to
     * point to a DOM element. But we're interested in logging
     * when it happens.
     */
    if (ref.current) {
      console.log(ref.current)

      /**
       * Try commenting and uncommenting the next line, and see
       * the amount of renderings
       */
       setState('bar');
    }

  }, [ref]);

  renderCounter = renderCounter + 1
  console.log(renderCounter);

  return <div ref={el}>simple</div>
}

React will re-render when the ref has been initialized with a value, but that doesn't mean it will happen on the 2nd render.

To answer your question, you haven't told react what to do when ref changes.

Sign up to request clarification or add additional context in comments.

1 Comment

The ref object is a mutable object the holds the same reference across re-renders. adding it as a dependency to useEffect will not retrigger the effect. the reason it logs the correct value is because useEffect runs after the render phase
0
class SimpleComponent extends React.Component{
  el = React.createRef(null)
  constructor(props){
    super(props)
    this.state = {
      st:0
    }
  }
  componentDidMount(){
    if(this.state.st<1)
      this.setState(prevState=>{
        return {st:prevState.st+1}
      })
  }

  render(){
    console.log('el.current',this.el.current,'st',this.state.st)
    return <div ref={this.el}>simple</div>
  }
}

ReactDOM.render(<SimpleComponent />,document.querySelector('#root') );

Output is

el.current null st 0
el.current <div>​simple​</div>​ st 1

According to Documentation

ReactDOM.render(element, container[, callback])

Render a React element into the DOM in the supplied container and return a reference to the component (or returns null for stateless components).

Since you are trying to reference a functional component it might be reason.It is interesting scenario i came across because of your question.

Also if used as child component the output is as expected

Comments

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.