Actualmente estoy construyendo un componente de icono en ReactJS, tendrá quizás 50-100 iconos, todos usando SVG y datos de ruta.

Me encuentro en una situación en la que quiero saber qué ruta avanzaría mejor y por qué dicha ruta sería la mejor opción. He pensado en dos opciones que podrían ser viables y podrían ver beneficios en ambas.


Opción 1

  • Cree un componente llamado 'Icono'
  • Tome un accesorio llamado 'nombre' (esto hará referencia al nombre del icono)
  • Según el nombre del accesorio, muestre el svg apropiado
  • Un solo componente para todos los iconos

Opcion 2

  • Cree un componente llamado 'Icono'
  • Cree componentes individuales para cada icono, por ejemplo (ArrowLeft, Hamburger)
  • El componente individual hereda 'Icon' como padre
  • El componente principal contiene toda la información SVG
  • El componente hijo contiene solo datos de ruta
  • 50-100 componentes Icon

Opción 1

Comencé a codificar ambas opciones y realmente me gustaría recibir alguna entrada. Especialmente si hay un método mejor en el que no he pensado todavía.

Aquí hay un código: -


Opción 1

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled, { ThemeProvider } from 'styled-components';
import _ from 'lodash';
import '../../global.js';
import * as variable from '../../variables.js';

const iconList = {
    navigation: {
        arrowUp: 'path data here',
        hamburger: 'path data here'
  }
}

class Icon extends Component {
    constructor(props) {
        super(props);
    }

    render() {

        let width, height, data, name;

        width = this.props.width === undefined ? '25' : this.props.width;
        height = this.props.height === undefined ? '25' : this.props.height;

        name = this.props.name;

        _.forEach(iconList, function(value, key) {
            data = _.get(value, [name]);
        });


        const icon = <svg xmlns="http://www.w3.org/2000/svg" width={width} height={height} viewBox="0 0 25 25">
                         <path fill={this.props.color} d={data} fillRule="evenodd" />
                    </svg>;

        return (
                <IconStyle>
                    {icon}
                </IconStyle>
        )

    }
}

export default Icon;

Opción 2 - (Icon.js)

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import styled, { ThemeProvider } from 'styled-components'

import '../../global.js';
import * as variable from '../../variables.js';

const IconStyle = styled.div `
    display:inline-block;
`;

class Icons extends Component {
    constructor(props) {
        super(props);
    }

    render() {

        let width, height;

        width = this.props.width === undefined ? '25' : this.props.width;
        height = this.props.height === undefined ? '25' : this.props.height;


        const icon = <svg xmlns="http://www.w3.org/2000/svg" width={width} height={height} viewBox="0 0 25 25">
                         <path fill={this.props.color} d={this.props.data} fillRule="evenodd" />
                    </svg>;

        return (
                <IconStyle>
                    {icon}
                </IconStyle>
        )

    }
}


export default Icons;

Opción 2: Hamburger.js (hereda el icono)

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

import '../../../global.js';
import * as variable from '../../../variables.js';
import Icon from '../Icon';

class NavigationHamburger extends Component {
    constructor(props) {
        super(props);
    }

    render() {


        let data = "M6.34 8.14c-.45 0-.8-.36-.8-.8 0-.45.35-.8.8-.8h12c.44 0 .8.35.8.8 0 .44-.36.8-.8.8h-12zm12 8.4c.44 0 .8.35.8.8 0 .44-.36.8-.8.8h-12c-.45 0-.8-.36-.8-.8 0-.45.35-.8.8-.8h12zm0-5c.44 0 .8.35.8.8 0 .44-.36.8-.8.8h-12c-.45 0-.8-.36-.8-.8 0-.45.35-.8.8-.8h12z";

        return (
                <Icon data={data} {...this.props} />           
        )

    }
}

NavigationHamburger.PropTypes = {
    data: PropTypes.string,
    color: PropTypes.color,
    width: PropTypes.boolean,
    height: PropTypes.boolean
}

export default NavigationHamburger;

Con la Opción 2 , simplemente llamaría al componente usando

<NavigationHamburger width={30} height={30} color="#000"/>

2
Adam 20 oct. 2017 a las 14:56

2 respuestas

La mejor respuesta

También optaría por el primer enfoque:

  1. Acercarse

    • + Menos código
    • + Más fácil de mantener (más rápido para agregar un nuevo ícono)
    • + Sin duplicación de código

    • - Posibilidad de errores tipográficos en el nombre (tal vez podría trabajar con algún tipo de enumeración de JavaScript)

  2. Acercarse

    • + Más fácil de usar (componentes definidos, sin nombres)

    • - Difícil de mantener (cambie el código en cada archivo)

    • - Más código masivo
    • - No escalable

Entonces tomaría el primer enfoque, pero también agregaré este archivo para un uso más fácil:

IconTypes.js:

const IconTypes = {
  HAMBURGER: 'hamburger'
}

export default IconTypes;

Ahora ha eliminado la posibilidad de errores tipográficos, ya que obtiene un error de pelusa. Ahora puede llamar al icono de esta manera (después de importar la clase Icon y IconType):

<Icon name={iconTypes.HAMBURGER} width={30} height={30} color="#000" />

Espero que esta respuesta te haya mostrado algunos puntos y te haya ayudado a tomar una decisión.

0
Larce 20 oct. 2017 a las 13:32

La opción 1 es bastante mejor en comparación con la opción 2 . En primer lugar, la reutilización juega su papel al máximo. Habrá un componente y lo usará cada vez con diferentes accesorios. En segundo lugar, si opta por la Opción 2 , la estructura del archivo será desordenada. Por desordenado, me refiero a que tendrá un archivo separado para cada icono y tendrá tiempo de sobrecarga mientras agrupa y compila. Para mejorar, le sugiero que lleve este mapeo de ruta a otro archivo y no lo haga en el componente:

const iconList = {
  navigation: {
    arrowUp: 'path data here',
    hamburger: 'path data here'
  }
}
0
Arslan Tariq 20 oct. 2017 a las 13:35