واکنش: الگوهای طراحی | اجزای ظرف

در دنیای React، یک الگوی طراحی به نام Container Components وجود دارد. اگر یک برنامهنویس React مبتدی یا متوسط هستید، ممکن است عادت داشته باشید که هر مؤلفه فرزند دادههای خود را بارگیری کند. به طور معمول، شما از قلاب هایی مانند useState
و useEffect
همراه با کتابخانه هایی مانند Axios یا Fetch برای دریافت اطلاعات از یک سرور. این کار می کند، اما زمانی که چندین مؤلفه فرزند نیاز دارند منطق یکسانی را به اشتراک بگذارند، ممکن است کثیف شود. اینجاست که اجزای ظرف وارد می شوند.
اجزای کانتینر تمام بارگذاری و مدیریت داده ها را برای اجزای فرزند خود مدیریت می کنند. آنها منطق واکشی داده ها را انتزاع می کنند و به اجزای فرزند اجازه می دهند تا تنها بر روی رندر تمرکز کنند. این تفکیک نگرانی ها کد شما را تمیزتر و قابل نگهداری تر می کند.
ایده اصلی
ایده اصلی پشت اجزای کانتینر مشابه اجزای طرح است. همانطور که مؤلفههای طرحبندی اطمینان میدهند که مؤلفههای فرزند نیازی به دانستن یا اهمیتی به چیدمان خود ندارند، مؤلفههای کانتینر نیز اطمینان میدهند که مؤلفههای فرزند نیازی به دانستن اینکه دادههایشان از کجا میآیند یا چگونه آنها را مدیریت کنند، ندارند. آنها فقط برخی از لوازم را می گیرند و هر آنچه را که برای نمایش نیاز دارند به نمایش می گذارند.
یک مثال ساده: CurrentUserLoader
بیایید با یک مثال ساده شروع کنیم. فرض کنید یک داریم CurrentUserLoader
مؤلفه ای که داده های کاربر فعلی را بارگیری می کند و آن را به a ارسال می کند UserInfo
جزء.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export const CurrentUserLoader = ({ children }) => {
const [user, setUser] = useState(null);
useEffect(() => {
const fetchData = async () => {
const response = await axios.get('/current-user');
setUser(response.data);
};
fetchData();
}, []);
return (
<>
{React.Children.map(children, child => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { user });
}
return child;
})}
>
);
};
در این مثال، CurrentUserLoader
دادههای کاربر فعلی را واکشی میکند و آنها را بهعنوان یک به فرزندان خود ارسال میکند user
پشتیبانی این UserInfo
سپس کامپوننت می تواند از این پایه برای نمایش اطلاعات کاربر استفاده کند.
انعطاف پذیرتر کردن: UserLoader
این CurrentUserLoader
مفید است اما محدود است. فقط داده های کاربر فعلی را بارگیری می کند. اگر بخواهیم اطلاعات هر کاربر را با شناسه آنها بارگذاری کنیم، چه؟ ما می توانیم انعطاف پذیرتر ایجاد کنیم UserLoader
جزء.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export const UserLoader = ({ userId, children }) => {
const [user, setUser] = useState(null);
useEffect(() => {
const fetchData = async () => {
const response = await axios.get(`/users/${userId}`);
setUser(response.data);
};
fetchData();
}, [userId]);
return (
<>
{React.Children.map(children, child => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { user });
}
return child;
})}
>
);
};
اکنون، UserLoader
می تواند داده های هر کاربر را با شناسه خود بارگیری کند و به فرزندان خود منتقل کند.
Going Generic: ResourceLoader
ما می توانیم این مفهوم را حتی با ایجاد یک عمومی فراتر ببریم ResourceLoader
مؤلفه ای که می تواند هر نوع منبعی را از سرور بارگیری کند.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
export const ResourceLoader = ({ resourceUrl, resourceName, children }) => {
const [state, setState] = useState(null);
useEffect(() => {
const fetchData = async () => {
const response = await axios.get(resourceUrl);
setState(response.data);
};
fetchData();
}, [resourceUrl]);
return (
<>
{React.Children.map(children, child => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { [resourceName]: state });
}
return child;
})}
>
);
};
با ResourceLoader
، می توانید هر منبعی را با تعیین URL و نام آن بارگیری کنید. این باعث می شود که این جزء بسیار قابل استفاده مجدد باشد.
انعطاف پذیری نهایی: منبع داده
در نهایت، اجازه دهید یک را ایجاد کنیم DataSource
مؤلفه ای که حتی نمی داند داده هایش از کجا آمده است. به جای اینکه منطق واکشی داده ها را کدگذاری کنیم، تابعی را ارسال می کنیم که داده ها را برمی گرداند.
import React, { useState, useEffect } from 'react';
export const DataSource = ({ getDataFunction, resourceName, children }) => {
const [state, setState] = useState(null);
useEffect(() => {
const fetchData = async () => {
const data = await getDataFunction();
setState(data);
};
fetchData();
}, [getDataFunction]);
return (
<>
{React.Children.map(children, child => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { [resourceName]: state });
}
return child;
})}
>
);
};
با DataSource
، می توانید داده ها را از هر منبعی بارگیری کنید – خواه یک API، ذخیره سازی محلی یا چیز دیگری باشد – با ارسال تابعی که داده ها را برمی گرداند.
نتیجه
کامپوننتهای Container یک الگوی قدرتمند در React هستند که به شما در مدیریت بارگذاری دادهها و منطق اشتراکگذاری در چندین مؤلفه کمک میکنند. با انتزاع کردن منطق واکشی داده در اجزای کانتینری مانند CurrentUserLoader
، UserLoader
، ResourceLoader
، و DataSource
، می توانید کد خود را تمیزتر و قابل نگهداری تر کنید. این تفکیک نگرانیها به اجزای فرزند شما اجازه میدهد تا تنها بر روی رندر تمرکز کنند و درک و گسترش برنامه شما را آسانتر میکند.
React: Design Patterns یک دوره آموزشی توسط Shaun Wassell است که می توانید آن را در LinkedIn Learning دنبال کنید.