۲۹ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

۸ قلاب React دیگر که باید در مورد آنها بدانید

useState شناخته شده ترین هوک برای استفاده از کامپوننت های کاربردی در React است، اما این فقط یک شروع است. در اینجا هشت قلاب React دیگر و نحوه استفاده از آنها آورده شده است.

useState شناخته شده ترین هوک برای استفاده از کامپوننت های کاربردی در React است، اما این فقط یک شروع است. در اینجا هشت قلاب React دیگر و نحوه استفاده از آنها آورده شده است.

React در میان فریمورک‌های جاوا اسکریپت UI همچنان سرعت‌سنج است. پیشرفت‌های زیادی در React وجود دارد، اما مهم‌ترین تغییر در چند سال اخیر، حرکت به سمت اجزای عملکردی بود. اجزای عملکردی برای بسیاری از قابلیت های خود به قلاب ها متکی هستند. رایج ترین قلاب useState است، اما بسیاری دیگر نیز وجود دارد.

در اینجا نگاهی به هشت قلاب React مفیدی که ممکن است در مورد آنها ندانید و نحوه استفاده از آنها می پردازیم.

useReducer

همه در مورد useState می‌دانند، زیرا یک ویژگی اساسی اجزای مبتنی بر کلاس – متغیرهای عضو برای نگهداری وضعیت – را با یک معادل تابعی جایگزین می‌کند. قلاب useReducer کاری مشابه انجام می‌دهد، اما برای سناریوهای پیچیده‌تر که در آن جابه‌جایی حالت بیشتر درگیر است و برنامه از شفاف‌سازی انتقال‌ها سود می‌برد. قلاب useReducer از کاهنده های موجود در Redux الهام گرفته شده است. می توان آن را به عنوان حد وسطی بین سادگی useState و پیچیدگی یک سیستم مدیریت دولتی مانند Redux در نظر گرفت.

در اینجا مثالی از نحوه کار با قلاب useReducer آورده شده است. همچنین می‌توانید کاهش‌دهنده را به صورت زنده در این JSFiddle مشاهده کنید.

 

const {useReducer, Fragment} = React;


const initialState = {
  text: "",
  isUpperCase: false,
};

const reducer = (state, action) => {
  switch (action.type) {
    case 'SET_TEXT':
      return {
        ...state,
        text: action.text,
      };
    case 'TOGGLE_UPPER_CASE':
      return {
        ...state,
        text: state.text.toUpperCase(),
      };
    case 'LOWERCASE':
      return {
        ...state,
        text: state.text.toLowerCase(),
      };
    default:
      return state;
  }
};

const App = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const handleChange = (event) => {
    dispatch({ type: 'SET_TEXT', text: event.target.value });
  };

  const handleToggleUpperCase = () => {
    dispatch({ type: 'TOGGLE_UPPER_CASE' });
  };

  const handleLowerCase = () => {
    dispatch({ type: 'LOWERCASE' });
  };

  return (
    <div>
      <input type="text" value={state.text} onChange={handleChange} />
      <button onClick={handleToggleUpperCase}>Toggle Upper Case</button>
      <button onClick={handleLowerCase}>Toggle Lower Case</button>
      <p>{state.text}</p>
    </div>
  );
};

هدف از این مثال این است که متن را از کادر ورودی گرفته و به کاربر اجازه دهید روی دکمه‌ها کلیک کند تا متن را با حروف بزرگ یا کوچک نمایش دهد. کد یک کاهنده جدید را با const [state, dispatch] = useReducer(reducer, initialState); اعلام می کند. useReducer تابع کاهنده و Initialstate را می گیرد و آرایه ای را برمی گرداند که سپس آن را برای حالت دادن و ارسال متغیرها از بین می بریم.

خود کاهنده با این موارد تعریف می‌شود: const reducer = (وضعیت، عمل) =>، که یک تابع دو آرگومان می‌دهد. هر زمان که تابع dispatch در کد فراخوانی شود، وضعیت فعلی را به همراه یک شی اکشن منتقل می کند. در این مورد، شی action دارای یک فیلد نوع است و ما از آن برای تعیین نحوه جهش وضعیت استفاده می کنیم.

در یک برنامه نسبتاً پیچیده، useReducer می‌تواند در مدیریت پیچیدگی مفید باشد و حتی می‌تواند با استفاده از زمینه در سراسر برنامه به اشتراک گذاشته شود. هنگامی که مدیریت useState به دلیل پیچیدگی برنامه دشوار است، قلاب useReducer می تواند کمک کند.

Civet: TypeScript بهتری؟

useCallback

قلاب useCallback یک قلاب عملکرد است. عملکردی را می گیرد و تضمین می کند که تنها یک نسخه برای همه تماس گیرندگان بازگردانده شده و مجددا استفاده می شود. اگر تابع گران باشد و به طور مکرر توسط یک حلقه یا مؤلفه های فرزند فراخوانی شود، قلاب useCallback می تواند عملکرد قابل توجهی را به دست آورد. این نوع بهینه سازی به عنوان یادآوری یک تابع شناخته می شود.

در فهرست ۲، نمونه ای از استفاده از useCallback برای استفاده از یک تابع در بسیاری از موارد موجود در لیست داریم. این مثال در JSFiddle زنده است.

 

const List = ({ items }) => {
  const [counter, setCounter] = React.useState(0);

  const incrementCounter = React.useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>
          {item} - {counter}
          <button onClick={incrementCounter}>Increment</button>
        </li>
      ))}
    </ul>
  );
};

ما از React.useCallback() برای ایجاد یک تابع ذخیره شده جدید در incrementCounter استفاده می کنیم. می‌توانیم تابع یادداشت‌شده را به‌عنوان یک تابع عادی در کنترل‌کننده onClick در فهرست استفاده کنیم. useCallback() یک تابع را به عنوان اولین آرگومان می گیرد. در آن عملکرد، ما می توانیم هر کاری را که نیاز داریم انجام دهیم. تفاوت اصلی این است که React به سادگی مقدار حافظه پنهان تابع را برمی گرداند، مگر اینکه چیزی در لیست متغیرهای وابستگی تغییر کرده باشد، که در مثال ما متغیر شمارنده است.

این یک قدرت جادویی گرانبها در مواردی است که نیاز دارید یک عملکرد گران قیمت را بین چندین تماس گیرنده به اشتراک بگذارید، به ویژه اجزای فرزند. به خاطر داشته باشید که وقتی به قلاب بعدی نگاه می کنیم (useMemo) که useCallback خود تابع را مخفی می کند. به عبارت دیگر، useCallback از ایجاد مجدد تابع واقعی هر بار که ظاهر می‌شود جلوگیری می‌کند و فقط در صورت لزوم آن را دوباره ایجاد می‌کند.

useMemo

قلاب useMemo خواهر و برادر useCallback است. در جایی که useCallback تابع را در حافظه پنهان ذخیره می کند، useMemo مقدار بازگشتی تابع را در حافظه پنهان ذخیره می کند. این یک تمایز ظریف است، اما مهم است.

چه زمانی باید از useMemo در مقابل useCallback استفاده کنید؟ پاسخ این است: زمانی که می توانید از useMemo و زمانی که مجبورید از useCallback استفاده کنید. قلاب useCallback زمانی شایسته است که عملکردی که از آن اجتناب می‌کنید، ایجاد خود تابع در رندر باشد، در حالی که useMemo از ایجاد مجدد تابع در هر کجا که ظاهر می‌شود جلوگیری نمی‌کند. . با این حال، useMemo اطمینان حاصل می کند که اگر وابستگی ها تغییر نکرده باشند، تابع یک مقدار ذخیره شده در حافظه پنهان را برمی گرداند.

فهرست ۳ useMemo را در یک مثال نشان می دهد. همچنین می‌توانید این مثال را در JSFiddle زنده مشاهده کنید.

 

const { useMemo, useState } = React;

const ExpensiveComputationComponent = () => {
  const [count, setCount] = useState(0);

  const computeExpensiveValue = (count) => {
    let result = 0;
    for (let i = 0; i < count * 10000000; i++) {
      result += i;
    }
    return result;
  };

  const memoizedValue = useMemo(() => computeExpensiveValue(count), [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <p>Expensive Value: {memoizedValue}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
    </div>
  );
};

در این مثال، تابعی داریم که محاسبه آن هزینه زیادی دارد: computeExpensiveValue. این بستگی به یک ورودی دارد، count. می‌توانیم از computeExpensiveValue(count), [count]) استفاده کنیم تا به react بگوییم: این تابع را فقط در صورتی اجرا کنید که تعداد تغییر کرده باشد. در غیر این صورت، محاسبات حافظه پنهان را برگردانید.

تاریخچه مختصری از روش شناسی چابک

باز هم، تفاوت با useCallback واضح نیست. تمایز مهم این است: useCallback قلابی است برای استفاده زمانی که خود تابع به طور مکرر نمونه‌سازی می‌شود و عملکردی را متحمل می‌شود. در غیر این صورت، useMemo انتخاب بهتری است.

useContext

در React، context یک محدوده متغیر است که خارج از کامپوننت‌ها وجود دارد و همه اجزا به آن دسترسی دارند. به این ترتیب، این یک فضای جهانی سریع و آسان برای داده های گسترده برنامه است. برای سناریوهای پیچیده، شاید بهتر باشد از یک فروشگاه داده رسمی مانند Redux استفاده کنید، اما برای بسیاری از موارد، context کافی است. قلاب useContext نحوه تعامل اجزای عملکردی با زمینه است.

در فهرست ۴، ما دو مؤلفه داریم، Speak و Happy که توسط مؤلفه والد برنامه، App استفاده می‌شود. کاربر می تواند بین حالت سگ و گربه جابجا شود و از طریق زمینه جهانی، اجزای کودک انتخاب را منعکس می کنند (مثلاً تکان دادن دم در مقابل خرخر کردن). همچنین می‌توانید JSFiddle زنده را برای این مثال بررسی کنید.

 

const { createContext, useContext, useState } = React;

const AnimalContext = createContext();

const Speak = () => {
  const { animalType } = useContext(AnimalContext);

  return (
    <div>
      {animalType === 'dog' ? 'woof' : 'meow'}
    </div>
  );
};

const Happy = () => {
  const { animalType } = useContext(AnimalContext);

  return (
    <div>
      {animalType === 'dog' ? 'wag tail' : 'purr'}
    </div>
  );
};

const App = () => {
  const [animalType, setAnimalType] = useState('dog');

  const toggleAnimalType = () => {
    setAnimalType(prevAnimalType => (prevAnimalType === 'dog' ? 'cat' : 'dog'));
  };

  return (
    <div>
      <button onClick={toggleAnimalType}>Toggle animal type</button>
      <div>{animalType}</div>
      <AnimalContext.Provider value={{ animalType }}>
        <Speak />
        <Happy />
      </AnimalContext.Provider>
    </div>
  );
};

useRef

قلاب useRef به شما امکان می دهد مرجعی را خارج از چرخه رندر مدیریت کنید. useState باعث می شود که موتور React در هنگام تغییر رندر شود، در حالی که useRef این کار را نمی کند. قلاب useRef مانند یک ناحیه خاص در کنار React است که می‌گوید: این متغیر خاص است و بخشی از رابط کاربری واکنش‌پذیر نیست. رایج ترین مورد استفاده برای useRef دسترسی مستقیم به DOM و API آن است. به طور معمول، در تفکر واکنشی، از این کار اجتناب می شود و همه چیز باید از طریق موتور واکنشی انجام شود، اما گاهی اوقات اجتناب ناپذیر است.

Prisma.js: کد اول ORM در جاوا اسکریپت

در فهرست ۵، هنگامی که روی دکمه کلیک می‌شود، از قلاب useRef برای نگه داشتن یک مرجع به فیلد ورودی استفاده می‌کنیم و از روش‌های DOM برای تمرکز روی آن و تنظیم مقدار آن استفاده می‌کنیم. “چیزی شگفت‌انگیز.” اینجا JSFiddle برای مثال userRef است.

 

const App = () => {
  const inputRef = React.useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
    inputRef.current.value="Something amazing";
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <App/>
);

useEffect

useEffect دومین قلاب رایج پس از useState است. اغلب برای برقراری تماس‌های API، تغییر DOM یا انجام اقدامات دیگر (یعنی ایجاد یک اثر) زمانی که چیزی در حالت جزء تغییر می‌کند، استفاده می‌شود. به یک معنا، useEffect به شما امکان می دهد یک متغیر یا متغیرهای واکنشی و رفتاری که برای آنها رخ می دهد را تعریف کنید.

در لیست ۶، یک لیست کشویی برای انتخاب شخصیت جنگ ستارگان تعریف می کنیم. وقتی این مقدار تغییر کرد، یک فراخوانی API با Star Wars API (SWAPI) برقرار می کنیم و داده های شخصیت را نمایش می دهیم. اینجا JSFiddle زنده برای این مثال است.

 

const { useState, useEffect } = React;

const StarWarsCharacter = () => {
  const [character, setCharacter] = useState('Luke Skywalker');
  const [data, setData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(`https://swapi.dev/api/people/?search=${character}`);
        const jsonData = await response.json();
        setData(jsonData.results[0]);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    fetchData();
  }, [character]);

  const handleCharacterChange = (event) => {
    setCharacter(event.target.value);
  };

  return (
    <div>
      <h1>Star Wars Character Details</h1>
      <select value={character} onChange={handleCharacterChange}>
        <option value="Luke Skywalker">Luke Skywalker</option>
        <option value="Han Solo">Han Solo</option>
        <option value="Princess Leia">Princess Leia</option>
      </select>
      {data ? (
        <div>
          <h2>{data.name}</h2>
          <p>Height: {data.height}</p>
          <p>Mass: {data.mass}</p>
          <p>Hair Color: {data.hair_color}</p>
        </div>
      ) : (
        <p>Loading...</p>
      )}
    </div>
  );
};

useLayoutEffect

useLayoutEffect یک قلاب کمتر شناخته شده است که زمانی که نیاز به اندازه گیری DOM رندر شده دارید، وارد عمل می شود. قلاب useLayoutEffect پس از ترسیم رابط کاربری توسط React فراخوانی می شود، بنابراین می توانید روی آن حساب کنید که به چیدمان واقعی دسترسی پیدا می کند.

در فهرست ۷، ما از useRef برای برداشتن عنصری از DOM و useLayoutEffect استفاده می‌کنیم تا پس از تکمیل رندر، مطلع شویم. سپس، اندازه عنصر را با استفاده از DOM API محاسبه می کنیم. همچنین JSFiddle را برای این مثال ببینید.

 

const { useState, useRef, useLayoutEffect } = React;

const App = () => {
  const [width, setWidth] = useState(null);
  const elementRef = useRef(null);

  useLayoutEffect(() => {
    if (elementRef.current) {
      const { width } = elementRef.current.getBoundingClientRect();
      setWidth(width);
    }
  }, []);

  return (
    <div>
      <div ref={elementRef}>Measure Width</div>
      <p>Width: {width}</p>
    </div>
  );
};

useImperativeHandle

گاهی اوقات، شما نیاز دارید که مرجع را مستقیماً به یک مؤلفه دریافت کنید. می‌توانید این کار را با useRef انجام دهید، و اگر می‌خواهید دسترسی به DOM مؤلفه را نیز فراهم کنید، می‌توانید از forwardRef استفاده کنید. با این حال، گاهی اوقات باید رفتاری را که مؤلفه از طریق مرجع نشان می دهد، سفارشی کنید. برای آن، به قلاب useImperativeHandle نیاز دارید.