Using react useRef() --why my ref is null? - reactjs

I have a simple example
function Node() {
const [hidden, setHidden] = useState(true);
const inputRef = useRef(null)
console.log(inputRef);
return (
<div>
{!hidden && <h2 ref={inputRef}>Hello World</h2>}
{hidden && <button onClick={() => setHidden(false)}>Show Child</button>}
</div>
)
}
Upon clicking the button, I would expect that the h2 DOM element is attached to my ref. However, I found that the ref.current is still null upon logging, but if I expand the object, it contains the DOM node.
How am I supposed to access the DOM element via my ref? At the time I want to reference it, for example inputRef.current.getBoundingClientRect(), it's always shown as null.
Your help is much appreciated!

You are trying to use the ref in the render phase, but the ref will be populate once React paint the screen, in the commit phase.
So, call it in a useEffect or useLayoutEffect
// run synchronously after all DOM mutations
React.useLayoutEffect(() => {
// do something with inputRef
}, [])

Your ref is not initialize when setHidden set to false if you want to use it you need some interactions like this
import React, { useRef, useState, useEffect } from 'react';
function App() {
const [hidden, setHidden] = useState(true);
const inputRef = useRef(null)
console.log(inputRef);
const handleChange=()=>{
console.log(inputRef);
}
useEffect(()=>{
console.log(inputRef);
},[hidden])
return (
<div>
<input onChange ={handleChange}></input>
{!hidden && <h2 ref={inputRef}>Hello World</h2>}
{hidden && <button onClick={() => setHidden(false)}>Show Child</button>}
</div>
)
}
export default App;

Related

In ReactJS, how can I assign multiple ref to a single DOM?

I have a dialogue component in which I have created a ref, but I also want to pass the ref from the parent to it. How can I do this?
import { forwardRef } from "react";
export const PopOver = ({
show = false,
...
}, ref) => {
const thisRef = useRef(null);
// dealing with UI changes with 'thisRef'
return (
<div
ref={thisRef}, // How can I add a `ref` here?
....
>
Hello world
</div>
);
};
export default forwardRef(PopOver);
You can wrap it with another element and pass parent ref to it
sth like this :
<div ref={ref}>
<div
ref={thisRef}
....
>
Hello world
</div>
</div>
or if you want to replace ref you can do it in useEffect
like this :
useEffect(()=>{
if(ref.current){
thisRef.current = ref.current
}
},[ref])

React input onChange not rerendering state when useState has default value

So this is working, input changes when I type.
const [editfield, setEdit_field] = React.useState();
function updateField(event) {
setEdit_field(event.target.value);
}
function editPost() {
setPostbody(<div><input onChange={updateField} value={editfield}></input></div>)
}
But when a put a default value in the useState it doesnt work anymore
const [editfield, setEdit_field] = React.useState(post.body);
function updateField(event) {
setEdit_field(event.target.value);
}
function editPost() {
setPostbody(<div><input onChange={updateField} value={editfield}></input></div>)
}
Access code here: https://codesandbox.io/s/brt7ok
You were setting JSX inside the state, that might be the issue, I have created a codesandbox demo which will help you in conditional Rendering
DEMO
You are rendering that function so when state will updated it re-run that function and resetting the value.
You can use below approach.
Take one state which represents the field is editable or not. And add condition with input component that it should only render when field is editable.
For example,
const [isEditable, setIsEditable] = useState(false);
<button onClick={() => setIsEditable(!isEditable)}>edit</button>
isEditable && (
<div>
<input onChange={updateField} value={editfield} />
</div>
)
For more idea, just put console before return. You will get idea.
Hope this helps :)
import React, { useState } from "react";
export default function App() {
let body = "hello";
const [editfield, setEditfield] = useState(body);
const [visible, setVisible] = useState(false);
function updateField(event) {
setEditfield(event.target.value);
}
function editPost() {
setVisible(true);
}
return (
<div>
<div>{visible?<div>
<input onChange={updateField} value={editfield}/>
</div>:body}</div>
<div>
<button onClick={editPost}>edit</button>
</div>
</div>
);
}

can we able to specify on click on the component definition itself?

I want to create a component(comp) with onclick event handler. which should be handled by the component itself (i.e. inside the comp.js file).
if I use it inside the parent component we don't need to specify the event but it is handled by the component element(comp element).
is this possible. Any idea to develop this one.
in ParentComponent.js current behavior.
<NewComponent onClick={clickBehaviour}/>
I want like,
In NewComponent.js
const NewComponent.js = ()=>{
// Some code
const clickBehaviour = () =>{
// click behaviour
}
}
Is it possible in the current standards?
why you want to write your onClick event in parent component?
you can do it inside NewComponent.js easily.
just do this:
import React from 'react'
function NewComponent() {
const clickBehaviour = () =>{
// click behaviour
}
return (
<div onClick={clickBehaviour}>
//some jsx here
</div>
)
}
export default NewComponent
and use in anywhere you want to use without onClick event :
< NewComponent />
i cant understand well you situation but you can use forwardRef if you want (also can use old getElementById but using forwardRef is recommended).
import React, { useRef } from "react";
const NewComponent = React.forwardRef((props, ref) => (
<div onClick={() => alert("div 2 clicked")} ref={ref}>
div 2
</div>
));
export default function App() {
const compRef = useRef(null);
return (
<div>
<NewComponent ref={compRef} onClick={() => {
compRef && compRef.current && compRef.current.click();
}} />
</div>
);
}

How to focus and select a checkbox using React ref?

I have been looking around a method to correctly focus and select a checkbox in React code.
The methods focus() and select() that I'm using in the example below are not working :
import React, { useRef } from "react";
export const HelloWorld = () => {
const checkboxref = useRef(null);
const handleOnClick = () => {
checkboxref.current.focus();
checkboxref.current.select();
};
return (
<div>
<button onClick={handleOnClick}>Focus</button>
<input type="checkbox" ref={checkboxref} />
</div>
);
};
When I click on the button, my checkbox is not focused and not selected...
Any solution please ?
Thank you so much.
You don't need to create a separate function to handle onChange event
const checkboxref = useRef(null);
You can simply get the current value of the checkbox with:
checkboxref.current.checked
// which returns a boolean
use this one it might help you. here I am using createRef instead of useRef and also uses the callback hook which ensures the availability of ref when you click the button.
import React,{createRef, useCallback} from 'react';
export const HelloWorld = () => {
const checkboxref = createRef();
const handleOnClick = useCallback(() => {
const node = checkboxref.current;
if(node){
node.focus();
node.select();
}
}, [checkboxref]);
return (
<div>
<button onClick={handleOnClick}>Focus</button>
<input type="checkbox" ref={checkboxref} />
</div>
);
};
The select methods selects text in elements such as text inputs and text areas, so I'm not sure what effect you expect it to have on the checkbox. As for focus, it can focus, but again, there is not much you can do with a focused checkbox. I can only think of styling it https://jsfiddle.net/4howanL2/1/

Accessing HTML elements inside a React component

I have a React component InputComponent which I cannot edit, and I would like to get a reference to one of its inner divs. (for example for the purpose of focusing on the input field).
const RefsExamplePage = () => {
return (
<div>
<div>
<InputComponent
title="Test component"
></InputComponent>
</div>
</div>
)
}
export default RefsExamplePage;
How do I achieve this?
which I cannot edit
If you can't edit it, the only thing you can do is pass ref to it and hope the InputComponent have refs implemented.
e.g.
const RefsExamplePage = () => {
// use inputRef.current to access the input reference
const inputRef = React.useRef()
return (
<div>
<div>
<InputComponent
ref={inputRef}
title="Test component"
/>
</div>
</div>
)
}
If this doesn't work or give you some error, you will need to modify the InputComponent
If InputComponent doesn't provide ref you can wrap its parent (the div container) then set ref for it:
import React, { useRef } from "react";
const RefsExamplePage = () => {
const container = useRef();
return (
<div>
<div ref={container}>
<InputComponent
title="Test component"
></InputComponent>
</div>
</div>
)
}
export default RefsExamplePage;
Then you can access the child element through the div's ref.
Use useRef() to create a ref to the component itself. This way you can get the components reference and you can use .current property of it to get the underlying DOM:
const RefsExamplePage = () => {
const inputRef = useRef();
const getInput = e => {
// here get the any dom node available
inputRef.current.querySelector('input').focus();
};
return (....
<InputComponent
ref={inputRef}
onClick={getInput}
title="Test component"/> // <---if no child are passed change to self closing
....)
}

Resources