نحوه مدیریت حالت در برنامه های React با API ها – Redux، Context API، و Recoil Examples
مدیریت حالت یک جنبه حیاتی در ساخت برنامههای React قوی و مقیاسپذیر است، بهویژه زمانی که با APIها سروکار داریم.
با افزایش پیچیدگی برنامه شما، مدیریت کارآمد وضعیت برای تجربه کاربری روان ضروری است.
در اکوسیستم React چندین گزینه برای مدیریت دولتی وجود دارد که هر کدام نقاط قوت و ضعف خاص خود را دارند. در این مقاله، سه راهحل محبوب مدیریت حالت را تحلیل میکنیم: Redux، Context API، و Recoil، و خواهیم دید که چگونه حالت را در زمینه تعاملات API مدیریت میکنند.
مقدمه ای بر مدیریت دولتی
قبل از پرداختن به جزئیات هر راه حل مدیریت ایالت، اجازه دهید به طور خلاصه بفهمیم که مدیریت دولتی چیست و چرا در توسعه React مهم است.
ایالت چیست؟
در React، state نشان دهنده داده هایی است که می توانند در طول زمان تغییر کنند. این چیزی است که به یک مؤلفه اجازه می دهد تا اطلاعات را پیگیری کند و هنگامی که آن اطلاعات تغییر می کند، دوباره ارائه شود. به عنوان مثال، یک جزء دکمه ممکن است وضعیتی برای ردیابی اینکه آیا روی آن کلیک شده است یا خیر، داشته باشد.
چرا ایالت را مدیریت کنیم؟
با رشد برنامه های React، مدیریت وضعیت پیچیده تر می شود. عبور حالت بین اجزا از طریق پایه ها می تواند دست و پا گیر شود و ممکن است منجر به "حفاری پایه" شود، جایی که داده ها را از لایه های زیادی از اجزا عبور می دهید.
هدف کتابخانه های مدیریت دولتی حل این مشکل با ارائه روشی متمرکز برای مدیریت و به اشتراک گذاشتن حالت بین اجزاء است.
Redux: مدیریت ایالتی آزمایش شده در نبرد
Redux سالهاست که یک کتابخانه مدیریت دولتی محبوب در اکوسیستم React بوده است. این مبتنی بر اصول یک جریان داده یک طرفه است و منبعی از حقیقت را برای کل حالت برنامه فراهم می کند.
نحوه نصب Redux
برای استفاده از Redux در پروژه React، باید هر دو بسته redux
و react-redux
را نصب کنید. ترمینال خود را باز کنید و دستور زیر را اجرا کنید:
npm install redux react-redux
این دستور کتابخانه اصلی Redux ( redux
) و پیوندهای رسمی React را برای Redux ( react-redux
) نصب می کند.
نحوه راه اندازی Redux
Redux از یک جریان داده یک طرفه پیروی می کند، به این معنی که داده ها در یک برنامه در یک جهت جریان می یابند و درک و مدیریت آن را آسان تر می کند. راهاندازی Redux شامل ایجاد یک فروشگاه برای نگهداری وضعیت برنامه، تعریف اقدامات برای توصیف تغییرات حالت و پیادهسازی کاهشدهندهها برای مدیریت این تغییرات است.
ایجاد فروشگاه Redux
فروشگاه Redux ظرفی است که کل درخت حالت برنامه شما را در خود جای می دهد. شما با ارسال یک تابع کاهنده به تابع createStore
از بسته redux
یک فروشگاه ایجاد می کنید.
// store.js import { createStore } from 'redux'; // Reducer const counterReducer = (state = { count: 0 }, action) => { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; default: return state; } }; // Store const store = createStore(counterReducer); export default store;
در کد بالا:
ما یک تابع کاهنده ( counterReducer
) ایجاد می کنیم که حالت فعلی و یک عمل را می گیرد، سپس بر اساس نوع عمل، حالت جدید را برمی گرداند.
فروشگاه با استفاده از createStore
ایجاد شده و با کاهش دهنده ما مقداردهی اولیه می شود.
نحوه تعامل با فروشگاه Redux در یک کامپوننت
برای تعامل با فروشگاه Redux در کامپوننت React، از useSelector
و useDispatch
hooks ارائه شده توسط react-redux
استفاده میکنیم.
// CounterComponent.js import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; const CounterComponent = () => { // Select the count from the store const count = useSelector((state) => state.count); // Get the dispatch function const dispatch = useDispatch(); return ( <div> <p>Count: {count}</p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button> </div> ); }; export default CounterComponent;
در CounterComponent
:
useSelector
به ما امکان می دهد داده ها را از فروشگاه Redux استخراج کنیم. در اینجا، ما count
از ایالت استخراج می کنیم.
useDispatch
دسترسی به تابع dispatch
را فراهم می کند و به ما امکان می دهد اقدامات را به فروشگاه Redux ارسال کنیم.
مزایای Redux
مدیریت وضعیت قابل پیشبینی: Redux یک جریان دادههای یک طرفه دقیق را اعمال میکند و آن را قابل پیشبینی و استدلال آسان میکند.
ابزارهای توسعه دهنده قدرتمند برای اشکال زدایی: Redux دارای ابزارهای توسعه دهنده قدرتمند مرورگر است که به شما امکان می دهد تغییرات وضعیت را در برنامه خود تحلیل و اشکال زدایی کنید.
پشتیبانی از میانافزار: Redux از میانافزار پشتیبانی میکند و شما را قادر میسازد تا با عوارض جانبی مانند عملیات ناهمزمان به روشی تمیز و سازماندهی شده مقابله کنید.
معایب Redux
کد دیگ بخار: Redux اغلب برای اعمال و کاهش دهنده ها نیاز به نوشتن کد دیگ بخار دارد که می تواند تکراری تلقی شود.
منحنی یادگیری تندتر: برای مبتدیان، مفاهیم اقدامات، کاهشدهندهها و میانافزار ممکن است منحنی یادگیری تندتری را در مقایسه با راهحلهای مدیریت حالت سادهتر ارائه دهند.
Redux یک کتابخانه مدیریت ایالتی آزمایش شده در نبرد است که در مدیریت وضعیت پیچیده در برنامه های کاربردی بزرگ عالی است. در حالی که ممکن است پیچیدگی اولیه و بویلر را معرفی کند، مزایای آن از نظر قابلیت پیش بینی، ابزارهای اشکال زدایی و پشتیبانی میان افزار، آن را به گزینه ای قدرتمند برای پروژه های مقیاس پذیر تبدیل می کند.
برای پروژههای کوچکتر، ممکن است بخواهید قبل از انتخاب Redux، مبادلات را در نظر بگیرید، زیرا جایگزینهای سادهتری مانند Context API یا Recoil ممکن است مناسبتر باشند.
Context API: سادگی با ویژگی داخلی React
Context API بخشی از خود React است و راهی برای عبور داده ها از درخت کامپوننت بدون نیاز به ارسال props به صورت دستی در هر سطح ارائه می دهد.
نحوه تنظیم Context API
Context API در React به شما این امکان را می دهد که حالت را بین اجزاء بدون عبور دستی از هر سطح از درخت مؤلفه به اشتراک بگذارید. راه اندازی Context API شامل ایجاد زمینه و استفاده از مؤلفه های Provider
و Consumer
است.
ایجاد یک زمینه
شما با ایجاد یک زمینه با استفاده از تابع createContext
شروع می کنید. این زمینه حالتی را که میخواهید به اشتراک بگذارید نگه میدارد.
// AppContext.js import { createContext } from 'react'; const AppContext = createContext(); export default AppContext;
ارائه و مصرف زمینه
سپس از مؤلفه Provider
برای بسته بندی بخشی از درخت مؤلفه خود که نیاز به دسترسی به حالت اشتراکی دارد استفاده می کنید. جزء Consumer
در اجزای فرزند برای دسترسی به زمینه استفاده می شود.
// AppProvider.js import React, { useReducer } from 'react'; import AppContext from './AppContext'; const initialState = { count: 0 }; const reducer = (state, action) => { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; default: return state; } }; export const AppProvider = ({ children }) => { const [state, dispatch] = useReducer(reducer, initialState); return ( <AppContext.Provider value={{ state, dispatch }}> {children} </AppContext.Provider> ); };
در این مثال:
ما یک کاهنده ساده داریم که تغییرات حالت را کنترل می کند.
مؤلفه AppProvider
فرزندان خود را با AppContext.Provider
میپوشاند و زمینه را در دسترس همه فرزندان قرار میدهد.
value
prop در Provider
روی یک شی حاوی وضعیت و یک تابع اعزام تنظیم می شود.
مصرف متن در یک جزء
اکنون، هر جزء در AppProvider
میتواند با استفاده از قلاب useContext
به حالت اشتراکگذاری شده دسترسی پیدا کند.
// CounterComponent.js import React, { useContext } from 'react'; import AppContext from './AppContext'; const CounterComponent = () => { const { state, dispatch } = useContext(AppContext); return ( <div> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button> </div> ); }; export default CounterComponent;
مزایای Context API
سادگی و سهولت استفاده: Context API روشی ساده و سرراست برای به اشتراک گذاشتن حالت بین اجزا بدون نیاز به تنظیمات اضافی ارائه میکند.
بدون نیاز به کتابخانه های اضافی: Context API در React تعبیه شده است که نیاز به کتابخانه های اضافی را از بین می برد و وابستگی ها را در پروژه شما کاهش می دهد.
داخلی برای React: از آنجایی که Context API بخشی از React است، میتوانید بدون هیچ گونه وابستگی خارجی از آن استفاده کنید.
معایب Context API
ممکن است منجر به رندرهای غیرضروری شود: Context API میتواند باعث رندرهای غیرضروری در مؤلفههایی شود که زمینه را مصرف میکنند، به خصوص اگر مقدار متن به طور مکرر تغییر کند. این به دلیل فقدان مکانیسم های بهینه سازی مانند یادداشت است.
محدود به موارد استفاده ساده تر: در حالی که برای بسیاری از سناریوها مناسب است، Context API ممکن است سطح کنترل و بهینه سازی مشابه کتابخانه های مدیریت دولتی اختصاصی مانند Redux یا Recoil را ارائه ندهد.
Context API یک راه حل مناسب برای به اشتراک گذاری حالت بین اجزاء است، به خصوص در برنامه های کوچکتر تا متوسط. سادگی و طبیعت داخلی آن، استفاده از آن را بدون معرفی کتابخانه های اضافی آسان می کند. با این حال، باید به مسائل احتمالی رندر مجدد توجه داشته باشید و راهحلهای مدیریت دولتی جایگزین را برای موارد استفاده پیچیدهتر در نظر بگیرید.
پس زدگی: رویکردی تازه به مدیریت دولتی
پس زدگی گفت ه نسبتاً جدیدتری به چشم انداز مدیریت دولتی است. این توسط فیس بوک توسعه یافته است و برای مدیریت وضعیت در برنامه های React انعطاف پذیرتر و شهودی تر طراحی شده است.
نحوه نصب Recoil
برای استفاده از Recoil در پروژه React، باید بسته recoil
را نصب کنید. ترمینال خود را باز کنید و دستور زیر را اجرا کنید:
npm install recoil
این دستور کتابخانه Recoil را نصب می کند که توسط فیس بوک توسعه یافته و برای مدیریت حالت در برنامه های React طراحی شده است.
نحوه تنظیم Recoil
پس زدگی مفهوم اتم ها را برای نمایش قطعات حالت و انتخابگرها برای استخراج مقادیر از آن حالت معرفی می کند.
ایجاد اتم ها
اتم ها واحدهای حالت در پس زدن هستند. شما اتم هایی را برای تعریف تکه های حالتی ایجاد می کنید که اجزا می توانند بخوانند و بنویسند.
// atoms.js import { atom } from 'recoil'; export const countState = atom({ key: 'countState', // unique ID (with respect to other atoms/selectors) default: 0, // default value (aka initial value) });
در این مثال، اتمی به نام countState
با مقدار اولیه 0
ایجاد کرده ایم.
استفاده از اتم ها در کامپوننت ها
می توانید از قلاب useRecoilState
برای خواندن و نوشتن روی اتم های اجزای خود استفاده کنید.
// CounterComponent.js import React from 'react'; import { useRecoilState } from 'recoil'; import { countState } from './atoms'; const CounterComponent = () => { const [count, setCount] = useRecoilState(countState); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> <button onClick={() => setCount(count - 1)}>Decrement</button> </div> ); }; export default CounterComponent;
در CounterComponent
، useRecoilState
برای دسترسی به مقدار فعلی countState
و تابع setCount
برای به روز رسانی آن استفاده می شود.
ایجاد انتخابگرها
انتخابگرها توابعی هستند که مقادیر را از یک یا چند اتم یا انتخابگرهای دیگر به دست می آورند. آنها ترکیب حالت مشتق شده را فعال می کنند.
// selectors.js import { selector } from 'recoil'; import { countState } from './atoms'; export const doubledCount = selector({ key: 'doubledCount', get: ({ get }) => { const count = get(countState); return count * 2; }, });
در این مثال، یک انتخابگر به نام doubledCount
ایجاد کردهایم که مقدار countState
را دو برابر میکند.
استفاده از انتخابگرها در کامپوننت ها
می توانید از قلاب useRecoilValue
برای خواندن مقادیر از انتخابگرها استفاده کنید.
// DoubledCounterComponent.js import React from 'react'; import { useRecoilValue } from 'recoil'; import { doubledCount } from './selectors'; const DoubledCounterComponent = () => { const doubledValue = useRecoilValue(doubledCount); return ( <div> <p>Doubled Count: {doubledValue}</p> </div> ); }; export default DoubledCounterComponent;
مزایای پس زدن
API شهودی با Minimal Boilerplate: Recoil یک API ساده را ارائه میکند، که کار با حالت را بدون معرفی تعداد زیادی کد دیگ بخار آسان میکند.
به طور خودکار واکنش پذیری را کنترل می کند: Recoil به طور خودکار واکنش پذیری را مدیریت می کند و اطمینان حاصل می کند که هنگام تغییر وضعیت های مربوطه، اجزا به روز می شوند.
پشتیبانی از ویژگی های پیشرفته مانند انتخابگرها: Recoil از ایجاد انتخابگرها پشتیبانی می کند و به شما امکان می دهد مقادیر حالت پیچیده را بر اساس اتم ها یا انتخابگرهای دیگر استخراج کنید.
معایب پس زدن
پشتیبانی اجتماعی نسبتاً جدید و محدود: Recoil به عنوان یک ورودی جدیدتر در فضای مدیریت ایالتی، ممکن است به اندازه کتابخانههای معتبرتری مانند Redux، پشتیبانی جامعه یا بستههای شخص ثالث گستردهای نداشته باشد.
Recoil یک کتابخانه مدیریت حالت امیدوارکننده است که یک API ساده و در عین حال قدرتمند برای مدیریت وضعیت در برنامه های React ارائه می دهد. در پروژه هایی که سادگی، واکنش پذیری و انعطاف پذیری را در اولویت قرار می دهند برتری دارد.
اما مطمئن شوید که بلوغ کتابخانه و نیازهای خاص پروژههای خود را هنگام انتخاب Recoil نسبت به جایگزینهای شناختهشدهتر مانند Redux یا Context API در نظر گرفتهاید. همانطور که Recoil تکامل مییابد و حمایت جامعه بیشتری را به دست میآورد، این پتانسیل را دارد که به یک راه حل پیشرو برای مدیریت حالت در برنامههای React تبدیل شود.
مدیریت دولتی با API ها
اکنون که درک اولیه ای از Redux، Context API و Recoil داریم، بیایید تحلیل کنیم که چگونه هر یک از این راه حل ها وضعیت را در زمینه تعاملات API کنترل می کنند.
نحوه واکشی داده ها از یک API با استفاده از Redux
بیایید سناریویی را در نظر بگیریم که در آن باید داده ها را از یک API واکشی کنیم و در برنامه React خود نمایش دهیم. ما از کتابخانه axios
برای ایجاد درخواست های API استفاده می کنیم.
در این مثال، ما از Redux برای مدیریت وضعیت پستهای واکشی شده از یک API استفاده میکنیم.
actions.js
// actions.js import axios from 'axios'; // Action creator for fetching posts export const fetchPosts = () => async (dispatch) => { try { // Make a GET request to the API const response = await axios.get('https://jsonplaceholder.typicode.com/posts'); // Dispatch an action to update the state with the fetched posts dispatch({ type: 'FETCH_POSTS', payload: response.data }); } catch (error) { // Dispatch an action in case of an error dispatch({ type: 'FETCH_ERROR', payload: error.message }); } };
این فایل حاوی یک تابع ایجاد کنش به نام fetchPosts
است.
Action creator یک تابع ناهمزمان است که اقدامات را بر اساس نتیجه درخواست API ارسال می کند.
ما از axios.get
برای درخواست GET به نقطه پایانی API مشخص شده استفاده می کنیم.
در صورت موفقیت آمیز بودن درخواست، اقدامی از نوع 'FETCH_POSTS'
ارسال می کنیم که محموله آن داده های دریافت شده از API است.
اگر در حین درخواست خطایی وجود داشته باشد، اقدامی از نوع 'FETCH_ERROR'
را با پیام خطا ارسال می کنیم.
postsReducer.js
// postsReducer.js const postsReducer = (state = { posts: [], error: null }, action) => { switch (action.type) { case 'FETCH_POSTS': // Update the state with the fetched posts and clear any existing error return { posts: action.payload, error: null }; case 'FETCH_ERROR': // Update the state with an error and an empty array of posts return { posts: [], error: action.payload }; default: // Return the current state if the action type doesn't match return state; } }; export default postsReducer;
این فایل حاوی یک تابع کاهنده به نام postsReducer
است.
کاهنده حالت فعلی (که دارای یک آرایه posts
و یک error
است) و یک عمل را می گیرد.
در مواردی که نوع اقدام 'FETCH_POSTS'
باشد، وضعیت را با پستهای واکشی شده بهروزرسانی میکند و خطاهای موجود را پاک میکند.
در مورد 'FETCH_ERROR'
، وضعیت را با یک پیام خطا به روز می کند و آرایه posts
را روی یک آرایه خالی تنظیم می کند.
اگر نوع عمل با هیچ یک از موارد مطابقت نداشته باشد، وضعیت فعلی را بدون تغییر برمیگرداند.
چگونه کار می کند
Action Creator ( fetchPosts
):
زمانی که میخواهید فرآیند واکشی پستها را آغاز کنید، خالق اقدام fetchPosts
فراخوانی میشود.
با استفاده از axios.get
یک درخواست API ناهمزمان ایجاد می کند.
اگر درخواست موفقیت آمیز باشد، اقدامی از نوع 'FETCH_POSTS'
با داده های واکشی شده به عنوان بار ارسال می کند.
اگر خطایی وجود داشته باشد، عملکردی از نوع 'FETCH_ERROR'
را با پیام خطا ارسال می کند.
کاهنده ( postsReducer
):
postsReducer
اقدامات ارسال شده را کنترل می کند.
هنگامی که عملکردی از نوع 'FETCH_POSTS'
دریافت می کند، وضعیت را با پست های واکشی شده به روز می کند و هر گونه خطای موجود را پاک می کند.
هنگامی که عملکردی از نوع 'FETCH_ERROR'
دریافت می کند، وضعیت را با یک پیام خطا به روز می کند و آرایه posts
را روی یک آرایه خالی تنظیم می کند.
اگر نوع عمل با هیچ یک از موارد مطابقت نداشته باشد، وضعیت فعلی را بدون تغییر برمیگرداند.
در معماری Redux، اکشنها به کاهندهها ارسال میشوند، که سپس وضعیت برنامه را بهروزرسانی میکنند. این مثال نشان می دهد که چگونه می توان از Redux برای مدیریت تغییرات حالت هنگام واکشی داده ها از یک API استفاده کرد. وضعیت به روشی قابل پیش بینی به روز می شود و مدیریت سناریوهای مختلف در برنامه را آسان تر می کند.
نحوه واکشی داده ها از یک API با استفاده از Context API:
در این سناریو، Context API برای مدیریت وضعیت پستهای واکشی شده از یک API و در دسترس ساختن آن برای اجزای برنامه React استفاده میشود.
AppContext.js
// AppContext.js import { createContext, useContext, useReducer, useEffect } from 'react'; import axios from 'axios'; // Creating a Context const AppContext = createContext(); // Initial state for the context const initialState = { posts: [], error: null }; // Reducer function to handle state changes const reducer = (state, action) => { switch (action.type) { case 'FETCH_POSTS': // Update state with fetched posts and clear any existing error return { posts: action.payload, error: null }; case 'FETCH_ERROR': // Update state with an error and an empty array of posts return { posts: [], error: action.payload }; default: // Return current state if the action type doesn't match return state; } }; // Context Provider component export const AppProvider = ({ children }) => { // useReducer hook to manage state and dispatch actions const [state, dispatch] = useReducer(reducer, initialState); // useEffect hook to fetch data when the component mounts useEffect(() => { const fetchData = async () => { try { // Make a GET request to the API const response = await axios.get('https://jsonplaceholder.typicode.com/posts'); // Dispatch an action to update the context state with fetched posts dispatch({ type: 'FETCH_POSTS', payload: response.data }); } catch (error) { // Dispatch an action in case of an error dispatch({ type: 'FETCH_ERROR', payload: error.message }); } }; // Fetch data when the component mounts fetchData(); }, []); // Empty dependency array to run the effect only once when the component mounts // Providing the context value to its descendants return ( <AppContext.Provider value={{ state, dispatch }}> {children} </AppContext.Provider> ); }; // Custom hook to conveniently consume the context export const useAppContext = () => { return useContext(AppContext); };
ایجاد یک زمینه:
createContext
برای ایجاد AppContext استفاده میشود که به عنوان محفظهای برای اشتراکگذاری حالت بین اجزا عمل میکند.
حالت اولیه و کاهنده:
شی initialState
وضعیت اولیه زمینه را نشان می دهد، از جمله یک آرایه خالی از پست ها و بدون خطا.
تابع reducer
تغییرات حالت را بر اساس اقدامات ارسال شده کنترل می کند. این حالت را بر اساس نوع عمل به روز می کند.
ارائهدهنده زمینه ( AppProvider
):
قلاب useReducer
برای مدیریت وضعیت و عملیات ارسال استفاده می شود.
قلاب useEffect
برای واکشی داده ها زمانی که کامپوننت سوار می شود استفاده می شود ( []
زیرا آرایه وابستگی اطمینان می دهد که فقط یک بار اجرا می شود).
در داخل fetchData
، Axios برای درخواست GET به نقطه پایانی API مشخص شده استفاده میشود.
بر اساس موفقیت یا عدم موفقیت درخواست، کاهش دهنده اقداماتی را برای به روز رسانی وضعیت زمینه ارسال می کند.
Context Consumer ( useAppContext
):
قلاب سفارشی useAppContext
از useContext
استفاده می کند تا به راحتی ارزش زمینه را در اجزاء مصرف کند.
نحوه استفاده در کامپوننت ها:
اجزای موجود در AppProvider
میتوانند از قلاب useAppContext
برای دسترسی به وضعیت اشتراکگذاری شده و عملیات ارسال استفاده کنند:
// ExampleComponent.js import React from 'react'; import { useAppContext } from './AppContext'; const ExampleComponent = () => { // Using the custom hook to access the context const { state, dispatch } = useAppContext(); return ( <div> <h2>Posts</h2> {state.posts.map((post) => ( <div key={post.id}> <h3>{post.title}</h3> <p>{post.body}</p> </div> ))} {state.error && <p>Error: {state.error}</p>} </div> ); }; export default ExampleComponent;
useAppContext
برای مصرف متن در ExampleComponent
استفاده می شود.
مؤلفه فهرستی از پستها را در صورت وجود ارائه میکند و در صورت بروز خطا در واکشی دادهها، پیام خطا را نمایش میدهد.
Context API، همراه با استفاده از قلابهای useReducer
و useEffect
، به شما امکان مدیریت و اشتراکگذاری حالت در بین اجزا را میدهد. AppProvider
زمینه را تنظیم می کند، داده ها را از API واکشی می کند و وضعیت زمینه را بر اساس نتایج به روز می کند. سپس مؤلفههای داخل ارائهدهنده میتوانند از قلاب useAppContext
برای دسترسی به وضعیت اشتراکگذاری شده استفاده کنند و اقدامات را در صورت نیاز ارسال کنند.
نحوه واکشی داده ها از یک API با استفاده از Recoil:
در این سناریو، Recoil برای مدیریت وضعیت پستهای واکشی شده از یک API و در دسترس قرار دادن آن برای اجزا در سراسر برنامه React استفاده میشود.
atoms.js
// atoms.js import { atom, selector } from 'recoil'; import axios from 'axios'; // Atom for posts state export const postsState = atom({ key: 'postsState', default: selector({ key: 'postsState/default', get: async () => { try { // Make a GET request to the API to fetch posts const response = await axios.get('https://jsonplaceholder.typicode.com/posts'); return response.data; } catch (error) { // Throw an error if the API request fails throw error; } }, }), });
اتم postsState
با استفاده از تابع atom
Recoil ایجاد می شود.
دارای یک مقدار پیشفرض است که توسط یک selector
تعریف شده است که با استفاده از axios.get
یک تماس API ناهمزمان برقرار میکند.
اگر تماس API موفقیت آمیز باشد، داده های واکشی شده برگردانده می شوند. اگر در حین فراخوانی API خطایی رخ دهد، پرتاب می شود.
PostsComponent.js
// PostsComponent.js import React from 'react'; import { useRecoilValue } from 'recoil'; import { postsState } from './atoms'; const PostsComponent = () => { // Using useRecoilValue hook to access the postsState atom const posts = useRecoilValue(postsState); return ( <div> <h2>Posts</h2> {posts.map((post) => ( <div key={post.id}> <h3>{post.title}</h3> <p>{post.body}</p> </div> ))} </div> ); }; export default PostsComponent;
PostsComponent
از قلاب useRecoilValue
برای دسترسی به مقدار اتم postsState
استفاده می کند.
سپس فهرست ی از پست ها را ارائه می کند، از طریق آرایه نقشه برداری می کند و عنوان و متن هر پست را نمایش می دهد.
نحوه استفاده در کامپوننت ها:
اجزای داخل RecoilRoot می توانند از قلاب های Recoil برای خواندن و نوشتن روی اتم ها استفاده کنند. در این مورد، useRecoilValue
برای خواندن مقدار اتم postsState
استفاده می شود.
// Example of using PostsComponent within a RecoilRoot import React from 'react'; import { RecoilRoot } from 'recoil'; import PostsComponent from './PostsComponent'; const App = () => { return ( <RecoilRoot> <div> <h1>My React App</h1> <PostsComponent /> </div> </RecoilRoot> ); }; export default App;
PostsComponent
در یک RecoilRoot
استفاده می شود که یک ارائه دهنده زمینه برای Recoil است.
این تضمین می کند که اجزای داخل RecoilRoot
می توانند به حالت Recoil دسترسی داشته باشند و از قلاب های Recoil استفاده کنند.
Recoil مدیریت حالت را در برنامه React ساده می کند. در این مثال، اتم postsState
برای مدیریت وضعیت پست های واکشی شده از یک API استفاده می شود. قلاب useRecoilValue
به کامپوننت ها اجازه می دهد تا به طور موثر مقدار اتم را بخوانند و داده ها را در رابط کاربری نمایش دهند. ساختار ارائه شده توسط Recoil اجازه می دهد تا یک روش تمیز و متمرکز برای مدیریت و به اشتراک گذاشتن حالت بین اجزاء.
نحوه به روز رسانی داده ها از طریق API با استفاده از Redux
اکنون، بیایید تحلیل کنیم که هر راه حل مدیریت ایالت چگونه به روز رسانی داده ها را از طریق درخواست های API مدیریت می کند. ما با Redux شروع می کنیم.
actions.js
// actions.js export const updatePost = (postId, updatedData) => async (dispatch) => { try { // Make a PATCH request to update a specific post by its ID const response = await axios.patch(`https://jsonplaceholder.typicode.com/posts/${postId}`, updatedData); // Dispatch an action to update the state with the updated post dispatch({ type: 'UPDATE_POST', payload: response.data }); } catch (error) { // Dispatch an action in case of an error dispatch({ type: 'FETCH_ERROR', payload: error.message }); } };
ایجاد کننده اکشن updatePost
برای مدیریت به روز رسانی یک پست با ایجاد یک درخواست PATCH
به API تعریف شده است.
این دو پارامتر را می طلبد: postId
(شناسه پستی که باید به روز شود) و updatedData
(داده های جدید پست).
در صورت درخواست موفقیت آمیز، اقدامی از نوع 'UPDATE_POST'
را با داده های پست به روز شده ارسال می کند.
اگر در حین درخواست API خطایی وجود داشته باشد، اقدامی از نوع 'FETCH_ERROR'
را با پیام خطا ارسال می کند.
postsReducer.js
// postsReducer.js const postsReducer = (state = { posts: [], error: null }, action) => { switch (action.type) { case 'UPDATE_POST': // Update the state with the updated post const updatedPosts = state.posts.map((post) => post.id === action.payload.id ? action.payload : post ); return { posts: updatedPosts, error: null }; // Other cases... default: // Return the current state if the action type doesn't match return state; } };
در postsReducer
، یک مورد 'UPDATE_POST'
اضافه می شود تا عملیات به روز رسانی را انجام دهد.
وضعیت با نقشه برداری از پست های موجود و جایگزینی یک شناسه منطبق با پست به روز شده به روز می شود.
این تضمین می کند که وضعیت به درستی با داده های جدید به روز می شود.
برای استفاده از این قابلیت در کامپوننت React، اقدام updatePost
را ارسال میکنید و شناسه پست و دادههای بهروز شده را ارائه میکنید. مثلا:
// Example of using updatePost in a React component import React from 'react'; import { useDispatch } from 'react-redux'; import { updatePost } from './actions'; const UpdatePostComponent = () => { const dispatch = useDispatch(); const handleUpdatePost = () => { // Example: Updating post with ID 1 and providing new data dispatch(updatePost(1, { title: 'Updated Title', body: 'Updated Body' })); }; return ( <div> <h2>Update Post</h2> <button onClick={handleUpdatePost}>Update Post</button> </div> ); }; export default UpdatePostComponent;
کامپوننت از قلاب useDispatch
برای دریافت تابع dispatch
استفاده می کند.
یک تابع handleUpdatePost
تعریف می کند که عمل updatePost
را با شناسه پست (1 در این مثال) و داده های به روز شده ارسال می کند.
این عملکرد می تواند با کلیک دکمه یا هر اقدام دیگر کاربر فعال شود.
این راهاندازی Redux به روشی تمیز و متمرکز برای مدیریت بهروزرسانی دادهها از طریق درخواستهای API اجازه میدهد. Action creator ( updatePost
) مسئول ایجاد درخواست API است و کاهش دهنده ( postsReducer
) اطمینان حاصل می کند که وضعیت بر اساس داده های دریافتی به درستی به روز شده است. مؤلفهها میتوانند از قلاب useDispatch
برای شروع این بهروزرسانیها از رابط کاربری استفاده کنند.
نحوه به روز رسانی داده ها از طریق API با استفاده از Context API:
AppContext.js
// AppContext.js export const AppProvider = ({ children }) => { // useReducer hook to manage state and dispatch actions const [state, dispatch] = useReducer(reducer, initialState); // Function to update a post via API const updatePost = async (postId, updatedData) => { try { // Make a PATCH request to update a specific post by its ID const response = await axios.patch(`https://jsonplaceholder.typicode.com/posts/${postId}`, updatedData); // Dispatch an action to update the context state with the updated post dispatch({ type: 'UPDATE_POST', payload: response.data }); } catch (error) { // Dispatch an action in case of an error dispatch({ type: 'FETCH_ERROR', payload: error.message }); } }; // Providing the context value with state, dispatch, and the updatePost function return ( <AppContext.Provider value={{ state, dispatch, updatePost }}> {children} </AppContext.Provider> ); };
تابع updatePost
به متن اضافه میشود، که یک درخواست PATCH
برای بهروزرسانی یک پست خاص با شناسه آن ایجاد میکند.
در صورت موفقیت آمیز بودن درخواست، اقدامی از نوع 'UPDATE_POST'
با داده های پست به روز شده ارسال می شود.
در صورت بروز خطا در حین درخواست API، اقدامی از نوع 'FETCH_ERROR'
را با پیام خطا ارسال می کند.
سپس تابع updatePost
در مقدار متن به همراه وضعیت و ارسال ارائه می شود.
نحوه استفاده در کامپوننت ها:
اجزای درون AppProvider
میتوانند از قلاب useContext
برای دسترسی به وضعیت اشتراکگذاری شده، ارسال و تابع updatePost
استفاده کنند.
// Example of using AppContext in a component import React, { useContext } from 'react'; import { AppContext } from './AppContext'; const UpdatePostComponent = () => { // Using useContext hook to access the context value const { updatePost } = useContext(AppContext); const handleUpdatePost = async () => { try { // Example: Updating post with ID 1 and providing new data await updatePost(1, { title: 'Updated Title', body: 'Updated Body' }); } catch (error) { // Handle error if needed console.error(error); } }; return ( <div> <h2>Update Post</h2> <button onClick={handleUpdatePost}>Update Post</button> </div> ); }; export default UpdatePostComponent;
UpdatePostComponent
از قلاب useContext
برای دسترسی به AppContext
استفاده می کند.
تابع updatePost
را از مقدار متن استخراج می کند.
مؤلفه یک تابع handleUpdatePost
را تعریف می کند که updatePost
با شناسه پست (1 در این مثال) و داده های به روز شده فراخوانی می کند.
این عملکرد می تواند با کلیک دکمه یا هر اقدام دیگر کاربر فعال شود.
Context API، همراه با استفاده از useReducer
و useContext
hooks، راهی برای مدیریت و به اشتراک گذاشتن حالت در بین اجزا فراهم می کند. AppProvider
زمینه را تنظیم می کند، از جمله توانایی به روز رسانی داده ها از طریق درخواست های API. مؤلفههای داخل ارائهدهنده میتوانند از قلاب useContext
برای دسترسی به وضعیت اشتراکگذاری شده، ارسال، و تابع updatePost
استفاده کنند، که به روشی متمرکز برای مدیریت بهروزرسانیها در برنامه اجازه میدهد.
نحوه به روز رسانی داده ها از طریق API با استفاده از Recoil:
atoms.js
// atoms.js export const postState = atomFamily({ key: 'postState', default: (postId) => selector({ key: `postState/${postId}`, get: async () => { try { // Make a GET request to fetch a specific post by its ID const response = await axios.get(`https://jsonplaceholder.typicode.com/posts/${postId}`); return response.data; } catch (error) { // Throw an error if the API request fails throw error; } }, }), });
postState
به عنوان یک atomFamily
تعریف می شود که امکان ایجاد اتم های جداگانه برای هر پست بر اساس شناسه آن را فراهم می کند.
هر اتم یک selector
با تابع get
است که یک درخواست GET
برای واکشی یک پست خاص با شناسه خود می دهد.
اگر درخواست موفقیت آمیز باشد، داده های پست را برمی گرداند. اگر خطایی وجود داشته باشد، خطا می دهد.
EditPostComponent.js
// EditPostComponent.js import React, { useState } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; import { postState } from './atoms'; const EditPostComponent = ({ postId }) => { // Using useRecoilValue to get the post data const post = useRecoilValue(postState(postId)); // Using useRecoilState to get and set the state of the post const [updatedTitle, setUpdatedTitle] = useState(post.title); const [updatedBody, setUpdatedBody] = useState(post.body); const handleUpdate = async () => { try { // Perform a PATCH request to update the specific post by its ID // with the updated title and body // Note: Actual API request code is missing in the provided example // You should implement the API request logic here console.log(`Updating post ${postId} with title: ${updatedTitle}, body: ${updatedBody}`); } catch (error) { // Handle error if needed console.error(error); } }; return ( <div> <input type="text" value={updatedTitle} onChange={(e) => setUpdatedTitle(e.target.value)} /> <textarea value={updatedBody} onChange={(e) => setUpdatedBody(e.target.value)} /> <button onClick={handleUpdate}>Update Post</button> </div> ); }; export default EditPostComponent;
EditPostComponent
از useRecoilValue
برای دریافت وضعیت فعلی پست خاص استفاده می کند.
از useRecoilState
برای دریافت و تنظیم وضعیت محلی عنوان و بدنه به روز شده استفاده می کند.
این مؤلفه فیلدهای ورودی را برای عنوان و متن ارائه میکند و به کاربران اجازه میدهد مقادیر بهروز شده را وارد کنند.
تابع handleUpdate
زمانی فراخوانی می شود که دکمه "به روز رسانی پست" کلیک شود. باید یک درخواست PATCH
برای به روز رسانی پست خاص با عنوان و بدنه جدید انجام دهد. منطق درخواست API واقعی در مثال ارائه شده وجود ندارد و باید طبق نقطه پایانی API پیاده سازی شود.
نحوه استفاده در کامپوننت ها:
برای استفاده از EditPostComponent
در یک RecoilRoot، آن را در کامپوننتی که با RecoilRoot
پیچیده شده است، رندر می دهید.
// Example of using EditPostComponent within a RecoilRoot import React from 'react'; import { RecoilRoot } from 'recoil'; import EditPostComponent from './EditPostComponent'; const App = () => { return ( <RecoilRoot> <div> <h1>My Recoil App</h1> <EditPostComponent postId={1} /> </div> </RecoilRoot> ); }; export default App;
EditPostComponent
در یک RecoilRoot
استفاده میشود که یک فراهمکننده زمینه برای Recoil است.
این تضمین می کند که اجزای داخل RecoilRoot
می توانند به حالت Recoil دسترسی داشته باشند و از قلاب های Recoil استفاده کنند.
Recoil's atomFamily
برای مدیریت وضعیت پستهای فردی استفاده میشود و EditPostComponent
نحوه استفاده از قلابهای Recoil را برای مدیریت بهروزرسانی دادهها از طریق درخواستهای API برای یک پست خاص نشان میدهد. EditPostComponent
به کاربران اجازه می دهد تا مقادیر جدیدی را برای عنوان و بدنه وارد کنند و تابع handleUpdate
باید به گونه ای گسترش یابد که منطق درخواست API واقعی برای به روز رسانی پست خاص را شامل شود.
نتیجه
در این مقاله ، ما سه راه حل مدیریت دولتی را برای برنامه های React مورد تحلیل قرار دادیم: Redux ، Context API و Recoil. هرکدام نقاط قوت و ضعف خاص خود را دارند و انتخاب بین آنها به نیازهای خاص و پیچیدگی پروژه شما بستگی دارد.
Redux: یک راه حل آزمایش شده با نبرد با یک رویکرد مدیریت دولت قابل پیش بینی. این امر در مدیریت حالت پیچیده در برنامه های بزرگ عالی است اما دارای یک منحنی یادگیری تندتر و کد دیگ بخار است.
زمینه API: یک ویژگی React داخلی که سادگی و سهولت استفاده را ارائه می دهد. این برای پروژه های کوچکتر مناسب است یا اینکه پیچیدگی Redux ممکن است بیش از حد باشد.
recoil: یک گفت نی نسبتاً جدیدتر با یک API بصری و انعطاف پذیری. Recoil یک انتخاب عالی برای پروژه هایی است که بدون قربانی کردن ویژگی های پیشرفته ، سادگی و واکنش پذیری را در اولویت قرار می دهند.
هنگامی که صحبت از وضعیت در زمینه تعامل API می شود ، می توان از هر سه راه حل به طور مؤثر استفاده کرد. Redux با پشتیبانی میان افزار خود ، API زمینه با سادگی خود ، و با ویژگی های واکنش پذیری آن ، همه راه هایی برای مدیریت حالت ضمن تعامل با API ها فراهم می کند. نکته مهم این است که انتخابی را انتخاب کنید که با نیازهای پروژه شما و آشنایی تیم شما با راه حل انتخاب شده مطابقت داشته باشد.
به یاد داشته باشید که نمونه های ارائه شده در این مقاله ساده شده است و در برنامه های دنیای واقعی ، ملاحظات اضافی مانند رسیدگی به خطا ، حالت های بارگیری و استراتژی های بهینه سازی باید در نظر گرفته شود.
در پایان ، مدیریت دولت جنبه مهمی در ساخت برنامه های React و درک نقاط قوت و تجارت Redux ، Context API و Recoil به شما امکان می دهد تا بر اساس نیازهای پروژه خود تصمیمات آگاهانه بگیرید.
از آنجا که اکوسیستم React همچنان در حال تکامل است ، ماندن در بهترین روشها و کاوش در راه حل های جدید به ایجاد برنامه های قابل نگهداری و مقیاس پذیر کمک می کند.
ارسال نظر