I have a functional component which causes the following error:
null is not an object (evaluating 'textInput.current.blur'
I wonder why
import React, { useState, useRef } from "react";
import { TextInput } from "react-native";
const UselessTextInput = ({ hide }) => {
const [text, onChangeText] = React.useState("Useless Text");
const textInput = useRef(null);
const _renderInput = () => {
if (hide) textInput.current.blur();
<TextInput
ref={textInput}
onFocus={() => ...}
onChangeText={onChangeText}
value={text} />
...
return __renderInput();
}
Can anyone explain this behaviour?
CodePudding user response:
If you set a ref to a DOM node using the ref
attribute, the ref's current
property will have that node only after it's set i.e. in useEffect
callbacks or from next renders.
function Counter() {
const [count, setCount] = React.useState(0);
const divRef = React.useRef("initval");
console.log("During Render", divRef.current);
React.useEffect(() => {
console.log("Inside useEffect CB", divRef.current);
}, []);
return <button ref={divRef} onClick={() => setCount(count 1)}>{count}</button>;
}
ReactDOM.render(<Counter />, document.getElementById("root"));
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
Understanding the flow:
When
useRef
is called React returns an object whosecurrent
property is set to the initial value provided ("initval"
in our case).So, the console log during first render prints the initial value.
Then the JSX is returned from the component, which updates the ref and sets it's
current
property to the DOM node.Then the callback passed
useEffect
runs and since the ref has already been updated it prints the DOM node.Then in next render (which can be triggered by clicking on the button), again we call
useRef
and React returns the same object and therefore this time the log during the render prints the DOM node.
CodePudding user response:
use optional chaining to your textInput
value
like this : textInput?.current?.blur();