Как я могу прикрепить ссылку к компоненту, который я копирую, используя React.cloneElement - PullRequest
2 голосов
/ 29 мая 2020

Привет, все, что я хочу передать в свой компонент, таким образом, я могу получить доступ к переменным в указанном компоненте, таком как состояние. Единственная проблема в том, что я не могу заставить его работать. Он должен иметь возможность работать как для классов, так и для функциональных

, что я получаю из консоли. Log каждый раз имеет значение null

  const testRef = createRef();
  console.log(testRef)
  const elementToCopy = singleScreenState.screen.peek().element;
  const Element = React.cloneElement(elementToCopy as ReactElement, { ...elementToCopy?.props, forwardRef: testRef })

1 Ответ

1 голос
/ 29 мая 2020

Ссылки на элемент 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" />
...