Cannot Read Property 'setattribute' of Undefined React Js Using Ref Not Id
In this post you'll learn how to utilise React.useRef() hook to create persisted mutable values (also known equally references or refs), too as admission DOM elements.
Table of Contents
- i. Mutable values
- one.i Use example: logging button clicks
- ane.two Use case: implementing a stopwatch
- two. Accessing DOM elements
- two.1 Use case: focusing an input
- 3. Updating references restriction
- iv. Summary
one. Mutable values
useRef(initialValue) is a built-in React hook that accepts one statement as the initial value and returns a reference (aka ref). A reference is an object having a special property electric current.
jsx
import { useRef } from 'react' ;
function MyComponent () {
const reference = useRef ( initialValue );
const someHandler = () => {
// Access reference value:
const value = reference . electric current ;
// Update reference value:
reference . current = newValue ;
};
// ...
}
reference.current accesses the reference value, and reference.current = newValue updates the reference value. Pretty simple.
There are two rules to remember well-nigh references:
- The value of the reference is persisted (stays the same) betwixt component re-renderings;
- Updating a reference doesn't trigger a component re-rendering.
Now, permit's see how to utilise useRef() in practice.
ane.one Utilize case: logging button clicks
The component LogButtonClicks uses a reference to shop the number of clicks on a button:
jsx
import { useRef } from 'react' ;
role LogButtonClicks () {
const countRef = useRef ( 0 );
const handle = () => {
countRef . current ++;
panel . log ( `Clicked ${ countRef . current } times` );
};
console . log ( 'I rendered!' );
render <button onClick = { handle } > Click me </push> ;
}
Attempt the demo.
const countRef = useRef(0) creates a references countRef initialized with 0.
When the push is clicked, handle function is invoked and the reference value is incremented: countRef.current++. The reference value is logged to the console.
Updating the reference value countRef.current++ doesn't trigger component re-rendering. This is demonstrated by the fact that 'I rendered!' is logged to the console just once, at initial rendering, and no re-rendering happens when the reference is updated.
Now a reasonable question: what's the main divergence betwixt references and land?
Reference and state diff
Let'due south reuse the component LogButtonClicks from the previous section, but this time utilize useState() claw to count the number of button clicks:
jsx
import { useState } from 'react' ;
function LogButtonClicks () {
const [ count , setCount ] = useState ( 0 );
const handle = () => {
const updatedCount = count + i ;
console . log ( `Clicked ${ updatedCount } times` );
setCount ( updatedCount );
};
console . log ( 'I rendered!' );
return <button onClick = { handle } > Click me </push button> ;
}
Try the demo.
Open the demo and click the button. Each time you lot click, you volition run into in the console the message 'I rendered!' — significant that each fourth dimension the state is updated, the component re-renders.
Then, the 2 primary differences between references and state:
- Updating a reference doesn't trigger re-rendering, while updating the state makes the component re-render;
- The reference update is synchronous (the updated reference value is bachelor right away), while the state update is asynchronous (the state variable is updated after re-rendering).
From a college bespeak of view, references shop infrastructure data of side-effects, while the state stores information that is direct rendered on the screen.
1.ii Utilize case: implementing a stopwatch
You can store inside a reference infrastructure data of side effects. For example, yous tin can shop into reference pointers: timer ids, socket ids, etc.
The component Stopwatch uses setInterval(callback, time) timer role to increase each second the counter of a stopwatch. The timer id is stored into a reference timerIdRef:
jsx
import { useRef , useState , useEffect } from 'react' ;
function Stopwatch () {
const timerIdRef = useRef ( 0 );
const [ count , setCount ] = useState ( 0 );
const startHandler = () => {
if ( timerIdRef . electric current ) { return ; }
timerIdRef . current = setInterval (() => setCount ( c => c + 1 ), 1000 );
};
const stopHandler = () => {
clearInterval ( timerIdRef . current );
timerIdRef . current = 0 ;
};
useEffect (() => {
render () => clearInterval ( timerIdRef . current );
}, []);
render (
<div>
<div> Timer: { count } south </div>
<div>
<button onClick = { startHandler } > Start </button>
<push onClick = { stopHandler } > Stop </button>
</div>
</div>
);
}
Try the demo.
startHandler() function, which is invoked when the Start push button is clicked, starts the timer and saves the timer id in the reference timerIdRef.electric current = setInterval(...).
To stop the stopwatch user clicks Finish push button. The Stop button handler stopHandler() accesses the timer id from the reference and stops the timer clearInterval(timerIdRef.current).
Additionally, if the component unmounts with the stopwatch active, the cleanup role of useEffect() is going to stop the timer as well.
In the stopwatch example, the reference was used to store the infrastructure data — the active timer id.
Side challenge: can y'all ameliorate the stopwatch by adding a Reset push button? Share your solution in a annotate beneath!
2. Accessing DOM elements
Some other useful application of the useRef() hook is to access DOM elements. This is performed in three steps:
- Define the reference to access the element
const elementRef = useRef(); - Assign the reference to
refattribute of the element:<div ref={elementRef}></div>; - Afterwards mounting,
elementRef.currentpoints to the DOM element.
jsx
import { useRef , useEffect } from 'react' ;
function AccessingElement () {
const elementRef = useRef ();
useEffect (() => {
const divElement = elementRef . current ;
console . log ( divElement ); // logs <div>I'chiliad an element</div>
}, []);
return (
<div ref = { elementRef } >
I'm an element
</div>
);
}
Try the demo.
2.1 Use case: focusing an input
Y'all would need to access DOM elements, for example, to focus on the input field when the component mounts.
To make information technology work yous'll need to create a reference to the input, assign the reference to ref attribute of the tag, and later mounting call the special method element.focus() on the element.
Here's a possible implementation of the <InputFocus> component:
jsx
import { useRef , useEffect } from 'react' ;
role InputFocus () {
const inputRef = useRef ();
useEffect (() => {
inputRef . current . focus ();
}, []);
return (
<input
ref = { inputRef }
blazon = "text"
/>
);
}
Attempt the demo.
const inputRef = useRef() creates a reference to concur the input element.
inputRef is then assigned to ref aspect of the input field: <input ref={inputRef} type="text" />.
React then, later mounting, sets inputRef.current to be the input chemical element. Now y'all tin can gear up the focus to the input programatically: inputRef.current.focus().
Ref is null on initial rendering
During initial rendering, the reference supposed to hold the DOM element is empty:
jsx
import { useRef , useEffect } from 'react' ;
part InputFocus () {
const inputRef = useRef ();
useEffect (() => {
// Logs `HTMLInputElement`
console . log ( inputRef . current );
inputRef . electric current . focus ();
}, []);
// Logs `undefined` during initial rendering
console . log ( inputRef . electric current );
return <input ref = { inputRef } blazon = "text" /> ;
}
Try the demo.
During initial rendering React however determines what is the output of the component, and then there'south no DOM structure created yet. That'southward why inputRef.current evaluates to undefined during initial rendering.
useEffect(callback, []) hook invokes the callback correct after mounting, when the input element has already been created in DOM.
callback part of the useEffect(callback, []) is the right place to admission inputRef.current because information technology is guaranteed that the DOM is constructed.
3. Updating references restriction
The function scope of the functional component should either calculate the output or invoke hooks.
That'south why updating a reference (equally well as updating land) shouldn't be performed within the immediate scope of the component'south office.
The reference must exist updated either inside a useEffect() callback or inside handlers (event handlers, timer handlers, etc).
jsx
import { useRef , useEffect } from 'react' ;
function MyComponent ({ prop }) {
const myRef = useRef ( 0 );
useEffect (() => {
myRef . current ++; // Good!
setTimeout (() => {
myRef . electric current ++; // Good!
}, 1000 );
}, []);
const handler = () => {
myRef . electric current ++; // Good!
};
myRef . electric current ++; // Bad!
if ( prop ) {
myRef . electric current ++; // Bad!
}
render <button onClick = { handler } > My button </button> ;
}
iv. Summary
useRef() hook creates references.
Calling const reference = useRef(initialValue) with the initial value returns a special object named reference. The reference object has a belongings current: you tin can use this property to read the reference value reference.current, or update reference.current = newValue.
Between the component re-renderings, the value of the reference is persistent.
Updating a reference, contrary to updating land, doesn't trigger component re-rendering.
References can too access DOM elements. Assign the reference to ref attribute of the chemical element you lot'd like to admission: <div ref={reference}>Element</div> — and the chemical element is bachelor at reference.current.
Want to improve yous React knowledge further? Follow A Simple Explanation of React.useEffect().
Challenge: write a custom claw useEffectSkipFirstRender() that works as useEffect(), merely that it doesn't invoke the callback later on initial rendering (Hint: you need to employ useRef()). Share your solution in a comment below!
Source: https://dmitripavlutin.com/react-useref-guide/
0 Response to "Cannot Read Property 'setattribute' of Undefined React Js Using Ref Not Id"
Post a Comment