最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How To Pass a Ref to a SVG Component in React - Stack Overflow

programmeradmin0浏览0评论

I have a svg ponent that is declared like so:


import {ReactComponent as Icon} from 'someplace.svg'

function SomeComponent(props){
   const [someState, setSomeState] = useState(0)
   const iconRef = useRef(null)

   useEffect(() => {
      //always prints null
      console.log(iconRef.current) 
   }, [someState])

return <div>
 <button onClick={() => setSomeState(prev => prev + 1)}>{someState}</button>
 <Icon ref={iconRef}/>
</div>
}

The problem here is that iconRef will always return null. I think this is because it is declared as a ponent so the ref would need to be forwarded directly to the svg tags but how do I do that?

Any ideas?

I have a svg ponent that is declared like so:


import {ReactComponent as Icon} from 'someplace.svg'

function SomeComponent(props){
   const [someState, setSomeState] = useState(0)
   const iconRef = useRef(null)

   useEffect(() => {
      //always prints null
      console.log(iconRef.current) 
   }, [someState])

return <div>
 <button onClick={() => setSomeState(prev => prev + 1)}>{someState}</button>
 <Icon ref={iconRef}/>
</div>
}

The problem here is that iconRef will always return null. I think this is because it is declared as a ponent so the ref would need to be forwarded directly to the svg tags but how do I do that?

Any ideas?

Share Improve this question edited Dec 8, 2020 at 13:24 prismo asked Dec 8, 2020 at 12:57 prismoprismo 1,9093 gold badges20 silver badges41 bronze badges 6
  • If someplace is a .svg file this code should work, how you know the ref is always null? Do you have a reproducible example? How to create a Minimal, Reproducible Example – Dennis Vash Commented Dec 8, 2020 at 13:15
  • Please show the Icon file, is it a ponent? If it does so your import is incorrect (probably). – Dennis Vash Commented Dec 8, 2020 at 13:16
  • @DennisVash yeah my bad. I updated the question with a reproducible working example – prismo Commented Dec 8, 2020 at 13:27
  • There is no problem in this code, please make a codesandbox demo – Dennis Vash Commented Dec 8, 2020 at 13:29
  • 1 @DowenRobinson did you find a solution ? Could you post it ? – Édouard Lopez Commented Mar 30, 2021 at 10:20
 |  Show 1 more ment

2 Answers 2

Reset to default 3

I'm not sure if this works in create-react-app, but it is dead anyway.

First you need to install svgr.

npm i @svgr/webpack

Add a svgr config file.

./.svgrrc.js

module.exports = {
  ref: true,
}

And a webpack config.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.svg$/i,
        use: ['@svgr/webpack'],
      },
    ],
  },
}

If using next insert the webpack config in next.config.js.

const webpack = require('webpack');

module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });
    return config;
  },
};

Then you can do something like:

import Icon from "@icons/icon.svg";

const IconWithRef () => {
  const ref = useRef<SVGSVGElement | null>(null);

  return (
      <Icon width="50" ref={ref} />
  );
};

You can check this sandbox for a working version.

UPDATE

Using this, I ran into some problems while using svg paths directly into .css files, because webpack resolves it as a react ponent. The workaround I could find to make both it work is by changing the webpack settings like so.

module.exports = {
  module: {
    rules: [
      {
        test: /\.svg$/i,
        type: 'asset',
        resourceQuery: /url/,
      },
      {
        test: /\.svg$/i,
        resourceQuery: { not: [/url/] },
        use: ['@svgr/webpack'],
      },
    ],
  },
}

And then using svg's paths in .css like:

.svg-background {
  background-image: url('../path/to/svg/image.svg?url');
}

Notice the ?url query param at the end.

Using the option issuer: /\.[jt]sx?$/, like in the docs, did not work for me.

This could be fixed in 3 steps:

  1. Get the SVG icon as a React Component in your codebase.
  2. Pass setRef to it.

Example:

Grab the SVG code into the ponent, like this:

const CloseIcon = (props) => (
  <svg
    width="38"
    height="38"
    viewBox="0 0 38 38"
    fill="none"
    xmlns="http://www.w3/2000/svg"
  >
    <circle cx="19" cy="19" r="18" stroke="#AFAFAF" stroke-width="2"></circle>
    <path
      d="M13.0548 13.336L24.9868 25.9185"
      stroke="#AFAFAF"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    ></path>
    <path
      d="M24.9862 13.3365L13.0542 25.9189"
      stroke="#AFAFAF"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    ></path>
  </svg>
)

export default CloseIcon

Then, in the Parent Component, where you use this icon, set its ref property, like:


...

const closeIconRef = createRef()
...

<CloseIcon
   style={{ position: 'absolute', top: 18, right: 18, cursor: 'pointer' }} 
   setRef={closeIconRef}
/>

Then add setRef to the tag in your SVG ponent:

const CloseIcon = ({ setRef }) => (
  <svg
    ref={setRef}
    width="38"
    height="38"
    viewBox="0 0 38 38"
    fill="none"
    xmlns="http://www.w3/2000/svg"
  >
...

You are done!

*The important thing to remember: the child nodes still are non-referenced, so it works if there are no shapes on the way of a hit. You can attach a ref to every child tho.

发布评论

评论列表(0)

  1. 暂无评论