Reputation: 4745
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') );
Upvotes: 2
Views: 22265
Reputation: 16288
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.
Upvotes: 5
Reputation: 498
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
Upvotes: 0