نوید بقولی‌زاده
نوید بقولی‌زاده
خواندن ۸ دقیقه·۴ سال پیش

استفاده‌ی صحیح از SVG در پروژه‌های React

استفاده‌ی صحیح svg در React
استفاده‌ی صحیح svg در React

چطوری از svg ها تو پروژه‌ات استفاده می‌کنی؟ جوری که استفاده می‌کنی چقدر در برابر تغییرات انعطاف‌پذیره؟ چقدر می‌تونی یه svg رو بارها و بارها استفاده کنی و هر بار تغییرات دلخواه خودت رو روی اون اعمال کنی؟

اگه مستقیما فایل‌های svg رو وارد پروژه‌ات می‌کنی و مثل یه عکس باشون رفتار می‌کنی، بهتره با خوندن این نوشته یه تجدید نظری روی رفتارت بکنی!

روش‌های معمول استفاده از SVG

اول می‌خوام 3 روش کلاسیکی که اکثراً استفاده می‌شه رو بهت نشون بدم. ?

1️⃣ استفاده از تگ img

import React from 'react'; import myLogo from './logo.svg'; const App = () => { return ( <div className=&quotApp&quot> <img src={myLogo} alt=&quotMy SVG Logo&quot /> </div> ); } export default App;

خب این پایه‌ترین حالت استفاده از یک svg هست که به شکل یک عکس باهاش رفتار می‌شه! قطعا هیچ دسترسی به خود svg نداری و نمی‌تونی مقادیری مثل رنگ svg رو از داخل کامپوننت خودت تغییر بدی.

2️⃣ استفاده از تگ SVG

import React from 'react'; const App = () => { return ( <div className=&quotApp&quot> <svg xmlns=&quothttp://www.w3.org/2000/svg&quot width=&quot200&quot height=&quot100&quot version=&quot1.1&quot> <rect width=&quot200&quot height=&quot100&quot stroke=&quotblack&quot stroke-width=&quot6&quot fill=&quotgreen&quot/> </svg> </div> ); } export default App;

توی این حالت هم می‌تونی محتوای فایل svg خودت رو مستقیما داخل یک تگ svg، داخل کامپوننت خودت استفاده کنی. قطعا دسترسی مستقیمی ایجاد می‌شه که می‌تونی با اجزای svg خودت بازی کنی و هر پارامتر رو که می‌خوای تغییر بدی یا ایجاد کنی. اما یه لحظه به حجم کد زیادی که ایجاد می‌شه فکر کن!

3️⃣ استفاده از SVG به عنوان یک کامپوننت

import React from 'react'; import {ReactComponent as MyLogo} from './logo.svg'; const App = () => { return ( <div className=&quotApp&quot> <MyLogo/> </div> ); } export default App;

به به، ببین کی اینجاس! از ریکت 16.3 به اینطرف اضافه شده و می‌تونی فایل‌های svg خودت رو به عنوان یک کامپوننت ریکت، مستقیماً import و استفاده کنی.


معایب استفاده از روش‌های کلاسیک

? روش اول رو قطعا بدترین روش ممکن خطاب می‌کنم. فرض کن 100 تا فایل svg داری. باید برای استفاده از اونها، هر 100 تا فایل رو داخل پروژه‌ات قرار بدی. همچنین به این روش، روش static می‌گن. یعنی svg ها قابل تغییر نیستند و باید هر آنچه که طراح گرافیکی بهت می‌ده رو قرار بدی. نه خبری از تغییر رنگ هست، نه خبری از تغییراتی که تو مدنظرته.

فرض کن قراره از آیکونت که به صورت svg عه، چندین جا استفاده کنی که رنگ‌های مختلفی دارند. همچنین قراره className های مختلفی بهشون بدی تا حساس به رخدادهای خاصی مثل hover باشند. می‌خوای چکار کنی؟ تو رو با اعمال زشتی که تا الآن انجام می‌دادی تنها می‌ذارم. ?

? روش دوم رو به عنوان کثیف‌ترین حالت انتخاب می‌کنم. خب OK! تو کل محتوای xml از فایل svg خودت رو داری و می‌تونی هر آشی که می‌خوای رو باهاش بپزی و تغییرش بدی. اما نهایتا با حجم زیادی از کدهای کثیف رو به رو می‌شی!

اگه کتاب‌های مرتبط با مبحث Clean Code رو خونده باشی، می‌دونی که این روش اصلا منطقی نیست! چون ممکنه از یک آیکون یا لوگو که به صورت svg هست، چندین جا استفاده کنی و قطعا copy و paste کردن جالب نیست. ممکنه داخل یک کامپوننت از تعداد زیادی svg استفاده کنی که منجر به افزایش حجم کد کامپوننتت بشه.

? و اما روش سوم که خیلی‌ مورد استفاده قرار می‌گیره اما باز هم مطابق میل من نیست. من این روش رو جاده خاکی حساب می‌کنم و نظرم اینه که باز هم تا جاده آسفالتی که قراره در ادامه بهش برسیم فاصله داره! دلیلش اینه که بازم پارامترهایی که از svg نیاز داری تغییر بدی رو نمی‌تونی دست‌کاری کنی.

برای مثال اگه بخوای یک صفت مشخص از svg خودت رو تغییر بدی، دسترسی مستقیم به مقدار اون نداری.

راه حل پیشنهادیِ استفاده از SVG

هدف، ایجاد یک کامپوننت مرجع برای کل svg های ماست که بتونیم هر کدوم از اون‌ها رو که می‌خوایم، فراخوانی کنیم و مقادیر دلخواه صفت‌های svg رو بهش بدیم. بیایید از روش دوم هم کمک بگیریم؛

قدم اول

یک فایل SVG.jsx حاوی یک svg xml رو ایجاد می‌کنیم و چند svg property رو به عنوان props ورودی مشخص می‌کنیم:

import React from 'react'; const SVG = ({ name = ' ', style = { }, fill = '#000000', viewBox = ' ', width = ' ', className = ' ', id = ' ', stroke = ' ' }) => ( <svg width={width} style={style} className={className} xmlns=&quothttp://www.w3.org/2000/svg&quot viewBox={viewBox} xmlnsXlink=&quothttp://www.w3.org/1999/xlink&quot id={id} > </svg> ); export default SVG;

قدم دوم

چی می‌خوای return کنی؟ قطعا یدونه svg که نیست! پس یه تابع بنویس و داخلش handle کن که بر اساس مقدار name به عنوان prop ورودی (می‌تونی از اسم‌های دیگه مثل moz، khiar و ... استفاده کنی ?)، کدوم svg رو برگردونی. حالا ما اینجا یک function به اسم getSVG ایجاد می‌کنیم:

من به ازای دو مقدار circle و rectangle، دو svg ساده رو قرار دادم که در ادامه می‌تونی نتیجه کار رو ببینی.
import React from 'react'; const getSVG = name => { switch (name) { case 'circle': return( <circle cx=&quot50&quot cy=&quot50&quot r=&quot40&quot stroke=&quotblack&quot stroke-width=&quot3&quot fill=&quotred&quot /> ); case 'rectangle': return( <rect width=&quot200&quot height=&quot100&quot stroke=&quotblack&quot stroke-width=&quot6&quot fill=&quotgreen&quot/> ); default: return <path /> } } const SVG = ({ name = ' ', style = { }, fill = '#000000', viewBox = ' ', width = ' ', className = ' ', id = ' ', stroke = ' ' }) => ( <svg width={width} style={style} className={className} xmlns=&quothttp://www.w3.org/2000/svg&quot viewBox={viewBox} xmlnsXlink=&quothttp://www.w3.org/1999/xlink&quot id={id} > {getSVG(name)} </svg> ); export default SVG;

و حالا جایی که می‌خوایم ازش استفاده کنیم:

import SVG from './SVG';
<SVG name=&quotcircle&quot /> <SVG name=&quotrectangle&quot />

نتیجه رو با هم ببینیم:

استفاده از svg
استفاده از svg

قدم سوم ( فینال )

ما به چیزی که می‌خواستیم رسیدیم و تموم svg هامون رو حالا داخل یک کامپوننت داریم. وقتشه از props های ورودیمون هم استفاده‌هایی بکنیم تا مثلا بتونیم به svg ها کلاس بدیم، رنگشون رو عوض کنیم و ...

برای مثال من اینجا مقدار fill و stroke رو از prop ورودی به اسم styles قرار می‌دهم.
import React from 'react'; const getSVG = (name, styles) => { switch (name) { case 'circle': return( <circle cx=&quot50&quot cy=&quot50&quot r=&quot40&quot stroke={styles.stroke} stroke-width=&quot3&quot fill={styles.fill} /> ); case 'rectangle': return( <rect width=&quot200&quot height=&quot100&quot stroke={styles.stroke} stroke-width=&quot6&quot fill={styles.fill}/> ); default: return <path /> } } const SVG = ({ name = ' ', style = { }, fill = '#000000', viewBox = ' ', width = ' ', className = ' ', id = ' ', stroke = ' ' }) => ( <svg width={width} style={style} className={className} xmlns=&quothttp://www.w3.org/2000/svg&quot viewBox={viewBox} xmlnsXlink=&quothttp://www.w3.org/1999/xlink&quot id={id} > {getSVG(name, {fill, stroke})} </svg> ); export default SVG;

و حالا جایی که می‌خوایم ازش استفاده کنیم:

import SVG from './SVG';
<SVG name=&quotcircle&quot fill=&quotblue&quot stroke=&quotred&quot/> <SVG name=&quotrectangle&quot fill=&quot#fff000&quot/>

نتیجه رو با هم ببینیم:

پس دیدیم که با واحد کردن کامپوننت SVG و انتخاب ورودی‌هایی مثل width، class، viewBox، fill و stroke ، می‌تونیم به راحتی و نامحدود به svg ها دسترسی داشته باشیم و هر کدوم رو به هر شکلی که میخوایم شخصی‌سازی کنیم.


این بود چرای اینکه از این روش استفاده کنیم. قطعا پروژه‌های با کیفیت، دیزاینرهای با کیفیت دارند و دیزاینرهای با کیفیت، لوگوها، آیکون‌ها و تصاویر با کیفیتی خلق می‌کنند. ما نیاز داریم تا بدونیم با svg ها چطور رفتار کنیم تا نتیجه رو به بهترین شکل ممکن نزدیک کنیم و از طرفی تیم توسعه رو در مسیری درست قرار بدیم. امیدوارم تونسته باشم به افزایش دانایی کسایی که به این قضیه نیاز داشتند، کمکی کرده باشم.

پیوست آخر!

  • ببین قبل از استفاده از هر یک از این 4 روش، نیازسنجی کن و ببین با توجه به scale پروژه‌ات، کدوم مورد نیاز تو هست. دلیل نمیشه بهترین راه پروژه‌ی X، بهترین راه پروژه‌ی Y باشه.
  • آقا جبهه نگیر که این چه کاریه و این داستان‌ها، اگه باهاش درگیر شی، متوجه میشی که داخل پروژه‌هایی با مقیاس بالا که از svg های زیادی استفاده می‌کنند و قراره به صورت پویا هم تغییر کنند، تو قطعاً به یک ساختار dynamic برای svg xml ها نیاز داری.
  • صحبت این نوشته با آیکون‌ها، لوگوها و عکس‌هایی بود که به صورت اختصاصی قراره استفاده بشن. پس خبری از fontawesome و امثال اون نیست.
  • برای خوانایی بیشتر، یک نمونه پروژه داخل github خودم قرار دادم که می‌تونی از لینک زیر ببینی ??
    https://github.com/NavidBgh/react-svg-component

و در آخر خوشحال می‌شم نظرات خودت رو باهام به اشتراک بذاری.

ممنون از چشم‌های خوشگلت که تا اینجا این نوشته رو همراهی کرد. ?

reactsvgریکتبرنامه‌نویسیوب
~ Go Where Your Dreams Take You ... ☘️?
شاید از این پست‌ها خوشتان بیاید