آشنایی با Context API در React - قسمت اول

البته با تاخیر می خوام در مورد React Context بنویسیم که از نسخه 16.3 معرفی شده و در نسخه های جدید تغییرات و بهبود بیشتری داشته. همانطورکه خود react تعریف کرده : context یک راه یا امکان رو برای شما فراهم می کنه که Data یا مثلا همون Prop هارو به یک سلسله کامپوننت با ساختار درختی پاس بدید بدون اینکه لازم باشه دونه به دونه با مشخص کردن Prop ها بصورت attribute در کامپوننت اطلاعات رو به کامپوننت های سطح پایین تر منتقل کنید و کلی دردسر و کدنویسی اضافه داشته باشید.

آشنایی با Context API در React
آشنایی با Context API در React

فرق Context با Prop drilling

مثال : فرض کنید یک کامپوننت دارید به نام </User> و قراره یکسری اطلاعات و اکشن که متدهای مختلف هستن رو به زیر مجموعه های خودش مثل لاگین, ویرایش پروفایل, تاریخچه ورود و ... انتقال بدید.

قبلا باید یکبار تمام این prop هارو به کامپوننت user انتقال می دادیم و اگر login داخلش بعنوان child بود یکبار هم به اون assign می کردید و اگر مثلا توی لاگین هم یک child دیگه داشتید و به prop ها احتیاج داشت یکبار به اون و اگر هزاربار هم این ساختار درختی جلو میرفت هزار بار به هزار کامپوننت prop هارو assign منتقل می کردیم که نه منطقی بنظر میاد و نه حجم کارش قابل قبوله. این روش رو Prop drilling میگن و قدیم تر خودمون بارها ازش استفاده کردیم.

React prop drilling vs. context API
React prop drilling vs. context API

البته با پکیج هایی مثل Redux هم این مسئله قابل حل هستش ولی اینجا می خوایم درمورد قابلیت built-in خود react یعنی context بیشتر صحبت کنیم و قطعا یکم با Redux مقایسه کنیم ببینیم چی میشه. دیگه با context مثل prop drilling عمل نمی کنیم و یکبار prop ها تعریف میشه و هزار بار راحت تر استفاده میشن.

استفاده از Context در React

می خوام با مثال User این امکان رو توضیح بدم :

import React, { createContext } from 'react';
import Profile from './components/Profile';
const UserData = {
    name: 'Mohammad Esmaeilzadeh',
    title: 'Front-end Developer',
    url: 'https://virgool.io/@buglessir'
};
export const UserContext = createContext();
class User extends React.Component {
    render() {
        return (
            <UserContext.Provider value={UserData}>
                <Profile/>
            </UserContext.Provider>
        );
    }
}

برای ساخت یک Context در ابتدا اومدیم createContext رو در خط اول import کردیم و در خط شماره 10 یک context به نام UserContext رو ایجاد کردیم و البته export شده که بعدا باید جای دیگه import بشه. در خط شماره 4 هم یک متغیر حاوی اطلاعات user بصورت تست و mock data درست کردیم که اطلاعات کاربر هستش. در خط 12 هم یک کلاس معمولی نوشتیم که کامپوننت User هستش و یک render و return داره.

برای اینکه prop ها یا data های مربوط به context رو به کامپوننت های child منتقل کنیم باید مثل redux یک provider داشته باشیم و مثل اونجا که store رو به زیر مجموعه ها پاس میدادیم اینجا اطلاعات user که همون متغیر UserData هستش رو پاس بدیم و به قولی Provider یک نوع wrapper بشه و زیر مجموعه های خودش رو پوشش بده.

این کار رو در خط شماره 15 تا 17 انجام دادیم و اول اسم context رو نوشتیم و بعد provider رو و سپس یک prop به اسم value که کل دیتا رو قراره بگیره و به زیر مجموعه منتقل کنه. کامپوننت Profile هم که قبلا در خط شماره 2 کد import شده بود رو بین این provider قرار میدیم که بتونه از اطلاعات استفاده کنه.

حالا کد کامپوننت Profile و نحوه دریافت اطلاعات از context :

import React from 'react';
import { UserContext } from './components/User';
class Profile extends React.Component {
    render() {
        return (
            <UserContext.Consumer>
                {(user) => (
                    <div>
                        <strong>Name: <strong> {user.name}<br />
                        <strong>Title: <strong> {user.title}<br />
                        <strong>URL: <strong> {user.url}<br />
                    </div>
                )}
            </UserContext.Consumer>
        );
    }
}

اینجا داخل کامپوننت Profile در خط 2 متغیر UserContext رو که در خط 10 فایل قبلی export کرده بودیم رو باید import کنیم که باز بتونیم ازش استفاده کنیم. داخل بلاک return هم اینبار چون می خوایم از اطلاعات user استفاده کنیم داخل یک wrapper به نام consumer بایستی تمام کدهامون رو بنویسیم البته با این تفاوت که یک تابع prop-render (همین Arrow Function) قرار میدیم و بهش اینجا user رو بعنوان ورودی دادیم که داخل کامپوننت تمام مقادیر متغیر UserData رو داره از همین متغیر میگیره.

توجه داشته باشید که اگر باز قراره یک کامپوننت دیگه مثلا UserAvatar داخل این Profile قرار بگیره و این prop ها و اطلاعات بهش پاس داده بشه داخل همین consumer اون کامپوننت رو قرار میدید و دوباره داخل UserAvatar باید UserContext رو import و مثل Profile مجدد از طریق consumer به اطلاعات دسترسی داشته باشید و همین روش برای تمام child ها تکرار میشه.

نتیجه گیری

تا به اینجا با مفهوم Context API در React آشنا شدیم و دیدیم که چطور میشه اطلاعات یک کاربر در قابل متغیر رو به سایر component ها انتقال داد و با کاربرد Provider و Consumer آشنا شدیم. میشه گفت کلیت context رو خدمتتون توضیح دادم ولی خوب یکسری کارای دیگه مثل پاس دادن 2 یا 3 context رو میخوایم تمرین کنیم و کمی در مورد مزایا , معایب و تفاوت هایی که این روش با Redux داره صحبت کنیم که انشاءالله در مقالات بعدی خواهم نوشت.

موفق باشید