How to import an entire folder of SVG images (or how to load them dynamically) into a React Web App?

前端 未结 5 1680
挽巷
挽巷 2021-02-05 05:02

I have a component that takes in an :itemName and spits out an html bundle containing an image. The image is different for each bundle.

Here\'s what I have:



        
相关标签:
5条回答
  • 2021-02-05 05:34

    Instead of multiple SVG files you can use the single SVG sprite.

    SVG sprite can be generated from a directory of SVG files using svg-sprite-generator:

    svg-sprite-generate -d images -o images/sprite.svg
    

    Then use it like this:

    import React from 'react';
    import { NavLink } from 'react-router-dom';
    import sprite from './images/sprite.svg';
    
    export default (props) => (
      <NavLink className="hex" activeClassName="active" to={'/hex/' + props.itemName}>
        <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
          <use xlinkHref={`${sprite}#${props.itemName}`} />
        </svg>
      </NavLink>
    )
    
    0 讨论(0)
  • 2021-02-05 05:37

    Stumbled onto this issue - I initially had the "Accepted answer", but i caused http request for each and every svg, which triggered a rate limit. So I ended up with a combination the accepted answer and what @karthik proposed - using a loader in the request.context

    As of CRA 2.0 @svgr is included to import svg's as react components.

    const reqSvgs = require.context('!@svgr/webpack!flag-icon-css/flags/4x3', true, /\.svg$/)
    

    So here we combine an svg loader and require.context

    const flagMap = reqSvgs.keys().reduce((images, path) => {
      const key = path.substring(path.lastIndexOf('/') + 1, path.lastIndexOf('.'))
      images[key] = reqSvgs(path).default
      return images
    }, {})
    

    Then we map all these into a json object so we can use key lookup

    To render svg's in jsx:

    const Flag = flagMap['dk']
    return (
      <Flag />
    )
    

    And happy days, svgs included in bundle and no individual http requests

    0 讨论(0)
  • 2021-02-05 05:38

    You can simply make a function which takes a parameter "name" (your svg icon name) and return your svg code.

    import React from 'react' export function getIcon(name){ switch(name) { case 'back': return ( // your svg code here <svg></svg> ) } }

    And then you can import it anywhere and simply call it with icon name you want.

    import { getIcon } from './utils'
    render() {
      return (
        <div>
         <span>{ getIcon('back') }</span>
        </div>
      )
    }
    
    0 讨论(0)
  • 2021-02-05 05:44

    Best way is to use a node module like [SVG to React Loader] (https://github.com/jhamlet/svg-react-loader)

    0 讨论(0)
  • 2021-02-05 05:51

    If using React, I strongly suspect you are also using Webpack. You can use require.context instead of es6 import and Webpack will resolve it for you when building.

    require.context ( folder, recurse, pattern )
    
    • folder - String - Path to folder to begin scanning for files.
    • recurse - Boolean - Whether to recursively scan the folder.
    • pattern - RegExp - Matching pattern describing which files to include.

    The first line of each example ...

    const reqSvgs = require.context ( './images', true, /\.svg$/ )
    

    ... creates a Require Context mapping all the *.svg file paths in the images folder to an import. This gives us a specialized Require Function named reqSvgs with some attached properties.

    One of the properties of reqSvgs is a keys method, which returns a list of all the valid filepaths.

    const allSvgFilepaths = reqSvgs.keys ()
    

    We can pass one of those filepaths into reqSvgs to get an imported image.

    const imagePath = allSvgFilePaths[0]
    const image = reqSvgs ( imagePath )
    

    This api is constraining and unintuitive for this use case, so I suggest converting the collection to a more common JavaScript data structure to make it easier to work with.

    Every image will be imported during the conversion. Take care, as this could be a foot-gun. But it provides a reasonably simple mechanism for copying multiple files to the build folder which might never be explicitly referenced by the rest of your source code.

    Here are 3 example conversions that might be useful.


    Array

    Create an array of the imported files.

    const reqSvgs = require.context ( './images', true, /\.svg$/ )
    const paths = reqSvgs.keys ()
    
    const svgs = paths.map( path => reqSvgs ( path ) )
    

    Array of Objects

    Create an array of objects, with each object being { path, file } for one image.

    const reqSvgs = require.context ( './images', true, /\.svg$/ )
    
    const svgs = reqSvgs
      .keys ()
      .map ( path => ({ path, file: reqSvgs ( path ) }) )
    

    Plain Object

    Create an object where each path is a key to its matching file.

    const reqSvgs = require.context ('./images', true, /\.svg$/ )
    
    const svgs = reqSvgs
      .keys ()
      .reduce ( ( images, path ) => {
        images[path] = reqSvgs ( path )
        return images
      }, {} )
    

    SurviveJS gives a more generalized example of require.context here SurviveJS Webpack Dynamic Loading.

    0 讨论(0)
提交回复
热议问题