Ссылки на элемент React никогда не заполняются, пока соответствующий элемент не смонтирован. Итак, проблема заключалась в том, что вы слишком рано регистрировались.
У меня есть пример ниже, запущенный в функциональном компоненте, чтобы продемонстрировать создание ссылок и их регистрацию после монтирования рассматриваемого элемента с использованием useEffect
.
Другая проблема, которая может возникнуть у вас, заключается в том, что на основе кода, который я вижу, вы можете создавать ссылку в функции рендеринга компонента класса, что не будет работать, потому что у вас не будет доступа к ссылке переменная после ее визуализации. Обычно вы сохраняете переменную ref в качестве свойства экземпляра класса, чтобы вы могли получить к ней доступ, когда она вам понадобится.
Для работы с функциональными компонентами вам необходимо использовать forwardRef
в функциональный компонент как часть его определения. Перенаправленная ссылка может go на хук useImperativeHandle
или на другой элемент.
Немного больше информации в документации React по доступу к ссылкам :
Когда ссылка передается элементу в рендере, ссылка на узел становится доступной в текущем атрибуте ссылки.
const node = this.myRef.current;
Значение ссылки различается в зависимости от типа узла:
Когда атрибут ref используется в элементе HTML, ссылка, созданная в конструкторе с помощью React.createRef (), получает базовый элемент DOM в качестве своего текущего свойства.
Когда атрибут ref используется в компоненте пользовательского класса, объект ref получает смонтированный экземпляр компонента как его текущий.
Вы не можете использовать атрибут ref в компонентах функции, потому что они не имеют
Последний пункт является ключевым моментом, который следует здесь отметить: React.ForwardRef позволяет вам дать функциональным компонентам возможность решать, что должен делать ref, потому что в противном случае ref в любом случае будет бессмысленным.
Как правило, в компонентах класса, если вы хотите передать ссылку через него, вы обычно должны передать его с отдельным именем свойства. Один из способов, показанных здесь: Как использовать React.forwardRef в компоненте на основе классов?
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 component', classRef.current.testFunct);
classRef.current.testFunct();
console.log('reference to a function component',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.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root" />