样式化组件 + 故事书:当我传递新样式时,SVG 图标不会重新渲染

Posted

技术标签:

【中文标题】样式化组件 + 故事书:当我传递新样式时,SVG 图标不会重新渲染【英文标题】:Styled components + Storybook: SVG Icon is not re-rendering when I pass new styles 【发布时间】:2021-07-21 06:20:26 【问题描述】:

我正在尝试创建一个 SvgIcon 组件,我通过道具将 SVG 传递给该组件。

由于 React 处理 SVG 的方式,当它们作为 ReactComponents 导入时(例如import ReactComponent as ArrowIcon from "icons/arrow.svg"),我必须以动态方式定义我的组件。

这是我目前所拥有的:

const styleSvgIcon = ( theme, stroke, fill, size, icon: Icon ) => styled(
  Icon
).attrs(
  viewBox: `0 0 24 24`,
)`
  path 
    $stroke && `stroke: $calculateColor( color: stroke, theme );`
    $fill && `fill: $calculateColor( color: fill, theme );`
  
  height: $calculateSize(size);
  width: $calculateSize(size);

`;

const SvgIcon = ( stroke, fill, size, icon ) => 
  const theme = useTheme();

  const StyledIcon = styleSvgIcon( theme, stroke, fill, size, icon );
  console.log('styledddddddddd', StyledIcon);  // prints the styled component with the new styles, but on the page nothing changes
  return <StyledIcon />;
;

SvgIcon.propTypes = 
  stroke: PropTypes.oneOf(Object.values(SVG_ICON_COLORS)),
  fill: PropTypes.oneOf(Object.values(SVG_ICON_COLORS)),
  size: PropTypes.oneOf(Object.values(SVG_ICON_SIZES)),
  icon: PropTypes.elementType.isRequired,
;

export default SvgIcon;

这是我的故事定义:

import React from 'react';
import SvgIcon from './SvgIcon';
import * as all_icons from '../icons';

import  SVG_ICON_SIZES, SVG_ICON_COLORS  from '../constants/variants';

export default 
  title: 'media/SvgIcon',
  component: SvgIcon,
  argTypes: 
    size: 
      type: 'select',
      options: Object.values(SVG_ICON_SIZES),
      defaultValue: SVG_ICON_SIZES.SMALL,
    ,
    stroke: 
      type: 'select',
      options: Object.values(SVG_ICON_COLORS),
      defaultValue: SVG_ICON_COLORS.PRIMARY,
    ,
    fill: 
      type: 'select',
      options: Object.values(SVG_ICON_COLORS),
      defaultValue: SVG_ICON_COLORS.PRIMARY,
    ,
  ,
;

const Template = (args) => 
  const icons = Object.values(all_icons);
  // return icons.map((SvgComponent, i) => (
  return icons
    .slice(0, 2)
    .map((SvgComponent, i) => (
      <SvgIcon key=i ...args icon=SvgComponent />
    ));
;

export const Small = Template.bind();
Small.args = 
  size: SVG_ICON_SIZES.SMALL,
;

export const Medium = Template.bind();
Medium.args = 
  size: SVG_ICON_SIZES.MEDIUM,
;

export const Large = Template.bind();
Large.args = 
  size: SVG_ICON_SIZES.LARGE,
;

export const XL = Template.bind();
XL.args = 
  size: SVG_ICON_SIZES.XL,
;

这在本地运行良好,但是当我部署我的应用并尝试通过 Storybook 更改道具时,没有任何更新。

但是,在生产中,控件什么都不做。

【问题讨论】:

【参考方案1】:

我想通了!!!

所以因为我只是设置样式而不使用这样的道具:

size: $calculate(size);

styled-components 以某种方式知道,因此不会将侦听器添加到更新的道具。所以我的StyledIcon 只是成为一个静态组件,在传入新样式时不会更新,因为它们只是一成不变的。

相反,将它们作为 props 传递并通过 props 访问它们会添加这些侦听器

const SvgIcon = ( stroke, fill, size, icon: Icon ) => 
  const StyledIcon = styled(Icon).attrs(
    viewBox: `0 0 24 24`,
  )`
    path 
      stroke: $( stroke, theme ) =>
        calculateColor( color: stroke, theme );
      fill: $( fill, theme ) => calculateColor( color: fill, theme );
    
    height: $( size ) => calculateSize(size);
    width: $( size ) => calculateSize(size);
  `;

  return (
    <div>
      <StyledIcon size=size fill=fill stroke=stroke />,size,fill,
      stroke
      <StyledArrowUpIcon stroke=stroke size=size fill=fill />
    </div>
  );
;

【讨论】:

以上是关于样式化组件 + 故事书:当我传递新样式时,SVG 图标不会重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

将样式组件与反应和故事书一起使用时未加载字体

使用样式化组件样式化 React 组件 (SVG)

故事书未显示样式

尝试将 :focus 样式应用于样式化组件内的嵌套 SVG

如何通过将 SVG 作为 prop 传递来使用 React 样式组件设置 SVG 样式?

如何使用样式化组件在 reactjs 中设置 svg 样式