简体   繁体   中英

How to use forwardRef correctly in a functional component?

I am trying to use functional components with hooks in React. I've used plenty of class components, but it seems like functional components are the new pattern for React, so I'm trying to make them work.

What I am trying to do is modify an SVG file I am loading when the user does something.

Here's the basics of my code:

function home() {

const appleRef = useRef({ value: null });

  useEffect(() => {
    if (typeof appleRef !== "undefined") {
      console.log(appleRef);
    }
  }, []);

return(
          <DiApple
            ref={appleRef}
            size={"3rem"}
            color={"black"}
            className="mi-home-card-icon mi-home-card-icon-apple"
          />
)
}

Which turns into this in the DOM:

<svg stroke="currentColor" fill="currentColor" stroke-width="0" version="1.1" viewBox="0 0 32 32" color="black" class="mi-home-card-icon mi-home-card-icon-apple" height="3rem" width="3rem" xmlns="http://www.w3.org/2000/svg" style="color: black;"><path d="M23.023 17.093c-0.033-3.259 2.657-4.822 2.777-4.901-1.512-2.211-3.867-2.514-4.705-2.548-2.002-0.204-3.91 1.18-4.926 1.18-1.014 0-2.583-1.15-4.244-1.121-2.185 0.033-4.199 1.271-5.323 3.227-2.269 3.936-0.58 9.769 1.631 12.963 1.081 1.561 2.37 3.318 4.061 3.254 1.63-0.064 2.245-1.055 4.215-1.055s2.524 1.055 4.248 1.021c1.753-0.032 2.864-1.591 3.936-3.159 1.24-1.814 1.751-3.57 1.782-3.659-0.038-0.017-3.416-1.312-3.451-5.202zM19.783 7.53c0.897-1.089 1.504-2.602 1.34-4.108-1.294 0.053-2.861 0.86-3.79 1.948-0.832 0.965-1.561 2.502-1.365 3.981 1.444 0.112 2.916-0.734 3.816-1.821z"></path></svg>

I want to be able to modify this SVG information on the user interacting with certain other DOM elements.

When I try to use this, I get the error:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Which from what I'm reading, I need to also add a forwardRef, because React needs it to be a component for some reason?

I'm not totally understanding the exact process here.

If someone could explain to me what my code should look like to be able to affect the SVG, as well as what exactly forwardRef is doing here and how it differs from class components, that would be massively helpful to me.

import React, { useEffect, useRef } from "react";
function Home() {
const appleRef = useRef({ value: null });//remove this ref
const svgRef = React.createRef();
const DiApple = React.forwardRef((props, ref) => {
  return (
    <svg
      ref={ref}
      stroke="currentColor"
      fill="currentColor"
      strokeWidth="0"
      version="1.1"
      viewBox="0 0 32 32"
      color="black"
      className="mi-home-card-icon mi-home-card-icon-apple"
      height="3rem"
      width="3rem"
      xmlns="http://www.w3.org/2000/svg"
      style={{ color: "black" }}
      {...props}
    >
      <path d="M23.023 17.093c-0.033-3.259 2.657-4.822 2.777-4.901-1.512-2.211-3.867- 2.514-4.705-2.548-2.002-0.204-3.91 1.18-4.926 1.18-1.014 0-2.583-1.15-4.244-1.121-2.185 0.033-4.199 1.271-5.323 3.227-2.269 3.936-0.58 9.769 1.631 12.963 1.081 1.561 2.37 3.318 4.061 3.254 1.63-0.064 2.245-1.055 4.215-1.055s2.524 1.055 4.248 1.021c1.753-0.032 2.864-1.591 3.936-3.159 1.24-1.814 1.751-3.57 1.782-3.659-0.038-0.017-3.416-1.312-3.451-5.202zM19.783 7.53c0.897-1.089 1.504-2.602 1.34-4.108-1.294 0.053-2.861 0.86-3.79 1.948-0.832 0.965-1.561 2.502-1.365 3.981 1.444 0.112 2.916-0.734 3.816-1.821z"></path>
  </svg>
  );
});

return (
  <DiApple
    ref={svgRef}
    size={"3rem"}
    color={"black"}
    className="mi-home-card-icon mi-home-card-icon-apple"
  />
);}

export default Home;

reference to svg is avaliable on the ref object created using React.createRef as follows svgRef.current

DiApple is a function component, and as explained in React documentation about forwarding refs , to define what ref will refer to on DiApple , you need to wrap it in a forwardRef call and pass the ref argument to your desired element:

const DiApple = React.forwardRef(function DiApple(props, ref) {
  return (
    <svg ref={ref}>
      {/* ... */}
    </svg>
  )
})

Next, I suggest passing null to useRef instead of { value: null } , that way appleRef.current will initially be null , then it will refer to the DOM node:

const appleRef = useRef(null);

useEffect(() => {
  if (appleRef.current !== null) {
    console.log(appleRef.current);
  }
}, []);

I recommend reading more about useRef .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM