hey all I want to pass in a ref into my ponent this way I can access the variables on said penent like state. only issue is i can't seem to get it to work. It needs to be able to work for both classes and functional
what I am receiving back from the console.log is null every time
const testRef = createRef();
console.log(testRef)
const elementToCopy = singleScreenState.screen.peek().element;
const Element = React.cloneElement(elementToCopy as ReactElement, { ...elementToCopy?.props, forwardRef: testRef })
hey all I want to pass in a ref into my ponent this way I can access the variables on said penent like state. only issue is i can't seem to get it to work. It needs to be able to work for both classes and functional
what I am receiving back from the console.log is null every time
const testRef = createRef();
console.log(testRef)
const elementToCopy = singleScreenState.screen.peek().element;
const Element = React.cloneElement(elementToCopy as ReactElement, { ...elementToCopy?.props, forwardRef: testRef })
Share
Improve this question
asked May 28, 2020 at 21:18
keilkeil
4331 gold badge6 silver badges15 bronze badges
1 Answer
Reset to default 9Refs to a React Element are never populated until the Element in question is mounted. So, the issue was that you were logging too early.
I have an example below running in a function ponent to demonstrate creating the refs and logging them once the element in question is mounted using useEffect
.
The other issue you might have is that based on the code I see, you might be creating the ref in the render function of a class ponent, which wouldn't work well because you wouldn't have access to the ref variable once it's actually rendered. Typically, you keep ref variable as an instance property of the class so you can access it when you need it.
For working with function ponents, you need to use forwardRef
on the function ponent as part of it's definition. The forwarded ref can go to the useImperativeHandle
hook, or to another element.
A little more info in React's Documentation on Accessing Refs:
When a ref is passed to an element in render, a reference to the node bees accessible at the current attribute of the ref.
const node = this.myRef.current;
The value of the ref differs depending on the type of the node:
When the ref attribute is used on an HTML element, the ref created in the constructor with React.createRef() receives the underlying DOM element as its current property.
When the ref attribute is used on a custom class ponent, the ref object receives the mounted instance of the ponent as its current.
You may not use the ref attribute on function ponents because they don’t have instances.
That last point is the key to note here: React.ForwardRef allows you to give the function ponents the ability to decide what a ref should do because otherwise the ref would be meaningless anyway.
In general in class ponents, if you want to pass a ref through it, you generally have to pass it down with a separate prop name. One of the ways shown here: How to use React.forwardRef in a class based ponent?
const { useRef, useEffect, useImperativeHandle } = React;
const TestFunction = React.forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
shout: () => console.log("I'm Yelling over here!")
}));
return <div>TestFunction</div>;
});
class TestComponent extends React.Component {
testFunct = () => {
console.log("testFunct works!");
};
render() {
return <div>TestComponent</div>;
}
}
function App() {
const elementRef = useRef();
const element = <div>Test</div>;
const clonedElement = React.cloneElement(element, { ref: elementRef });
const classRef = useRef();
const classElement = <TestComponent />;
const clonedClass = React.cloneElement(classElement, { ref: classRef });
const functionRef = useRef();
const functionElement = <TestFunction />;
const clonedFunction = React.cloneElement(functionElement, {
ref: functionRef
});
useEffect(() => {
console.log('reference to an element',elementRef.current);
// This produces weird output in the stack overflow console.
// console.log(classRef.current);
console.log('function from a reference to a class ponent', classRef.current.testFunct);
classRef.current.testFunct();
console.log('reference to a function ponent',functionRef.current);
functionRef.current.shout();
});
return (
<div className="App">
{clonedElement}
{clonedClass}
{clonedFunction}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root" />