إنشاء متجر عالمي يشبه Redux باستخدام React Hooks

مرحبا يا هبر! أقدم إليكم ترجمة المقال "إنشاء متجر عالمي يشبه الإعادة باستخدام React Hooks" بواسطة Ramsay.


دعونا نتخيل أنني كتبت مقدمة مثيرة للاهتمام لهذه المقالة ، والآن يمكننا أن نذهب مباشرة إلى الأشياء المثيرة للاهتمام حقًا. باختصار ، نحن سوف
استخدم useReducer و useContext لإنشاء ربط React مخصص يوفر الوصول إلى مستودع عمومي مشابه لـ Redux.


لا أفترض بأي حال من الأحوال أن هذا الحل هو المكافئ الكامل لـ Redux ، لأنني متأكد من أنه ليس كذلك. بقولك "استرجاع مثل ،" أعني ،
أنك ستقوم بتحديث المستودع باستخدام الإرسال والإجراءات ، مما يؤدي إلى تغيير حالة المستودع وإرجاع نسخة جديدة من الحالة المتغيرة.
إذا لم تستخدم Redux مطلقًا ، فما عليك سوى التظاهر بعدم قراءة هذه الفقرة.


الغياب


لنبدأ بإنشاء سياق ( يشار إليه فيما يلي باسم " السياق" ) سيحتوي على حالتنا ( يشار إليها فيما يلي باسم الولاية ) ووظيفة إرسال ( يشار إليها فيما يلي بالإرسال ). سنقوم أيضًا بإنشاء وظيفة useStore ، والتي سوف تتصرف مثل خطافنا .


// store/useStore.js import React, { createContext, useReducer, useContext } from "react"; //     const initialState = {} const StoreContext = createContext(initialState); // useStore    React       export const useStore = store => { const { state, dispatch } = useContext(StoreContext); return { state, dispatch }; }; 

نظرًا لأنه يتم تخزين كل شيء داخل سياق التفاعل ، فأنت بحاجة إلى إنشاء موفر سيعطيه
لنا كائن الدولة وظيفة الإرسال . المزود هو حيث نستخدم useReducer .


 // store/useStore.js ... const StoreContext = createContext(initialState); export const StoreProvider = ({ children }) => { const [state, dispatch] = useReducer(reducer, initialState); return ( <StoreContext.Provider value={{ state, dispatch }}> {children} </StoreContext.Provider> ); }; ... 

نحن نستخدم useReducer للحصول على الدولة والإيفاد . في الواقع ، هذا هو بالضبط ما يفعله useReducer . بعد ذلك ، نقوم بتمرير الحالة وإرسالها إلى المزود .
الآن يمكننا التفاف أي مكون React باستخدام <Provider /> ويمكن لهذا المكون استخدام useStore للتفاعل مع المستودع.


لم نقم بإنشاء المخفض حتى الآن . هذه ستكون خطوتنا التالية.


 // store/useStore.js ... const StoreContext = createContext(initialState); //    actions,     state const Actions = {}; // reducer   ,  action    dispatch // action.type -  ,     Actions //   update   state      const reducer = (state, action) => { const act = Actions[action.type]; const update = act(state); return { ...state, ...update }; }; ... 

أنا معجب جدًا بفصل الإجراءات والحالة إلى مجموعات منطقية ، على سبيل المثال: قد تحتاج إلى مراقبة حالة العداد (مثال كلاسيكي لتنفيذ العداد) أو حالة المستخدم (سواء قام المستخدم بتسجيل الدخول إلى النظام أو تفضيلاته الشخصية).
في بعض المكونات ، قد تحتاج إلى الوصول إلى كلتا هاتين الحالتين ، وبالتالي فإن فكرة تخزينها في مستودع عام واحد تعتبر منطقية تمامًا. يمكننا تقسيم إجراءاتنا إلى مجموعات منطقية مثل userActions و countActions ، مما يجعل إدارتها أسهل كثيرًا.


لنقم بإنشاء ملفات countActions.js و userActions.js في مجلد المتجر.


 // store/countActions.js export const countInitialState = { count: 0 }; export const countActions = { increment: state => ({ count: state.count + 1 }), decrement: state => ({ count: state.count - 1 }) }; 

 // store/userActions.js export const userInitialState = { user: { loggedIn: false } }; export const userActions = { login: state => { return { user: { loggedIn: true } }; }, logout: state => { return { user: { loggedIn: false } }; } }; 

في كلا الملفين ، نقوم بتصدير initialState ، لأننا نريد دمجها لاحقًا في ملف useStore.js في كائن initialState واحد.
نقوم أيضًا بتصدير كائن إجراءات يوفر وظائف لطفرات الحالة. لاحظ أننا لا نعيد كائن حالة جديد ، لأننا نريد أن يحدث هذا في المخفض ، في ملف useStore.js .


الآن نستوردها جميعًا إلى useStore.js للحصول على الصورة كاملة.


 // store/useStore.js import React, { createContext, useReducer, useContext } from "react"; import { countInitialState, countActions } from "./countActions"; import { userInitialState, userActions } from "./userActions"; //    (initial states) const initialState = { ...countInitialState, ...userInitialState }; const StoreContext = createContext(initialState); //  actions const Actions = { ...userActions, ...countActions }; const reducer = (state, action) => { const act = Actions[action.type]; const update = act(state); return { ...state, ...update }; }; export const StoreProvider = ({ children }) => { const [state, dispatch] = useReducer(reducer, initialState); return ( <StoreContext.Provider value={{ state, dispatch }}> {children} </StoreContext.Provider> ); }; export const useStore = store => { const { state, dispatch } = useContext(StoreContext); return { state, dispatch }; }; 

لقد فعلنا ذلك! قم بإنشاء دائرة شرف ، وعندما تعود ، سنرى كيف نستخدمها جميعًا في المكون.


اهلا بعودتك آمل أن تكون دائرتك مشرفة حقًا. دعونا نلقي نظرة على useStore في العمل.


أولاً يمكننا التفاف مكون التطبيق لدينا في <StoreProvider /> .


 // App.js import React from "react"; import ReactDOM from "react-dom"; import { StoreProvider } from "./store/useStore"; import App from "./App"; function Main() { return ( <StoreProvider> <App /> </StoreProvider> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<Main />, rootElement); 

نحن نلف التطبيق في StoreProvider حتى يتمكن المكون الفرعي من الوصول إلى القيمة من المزود. هذه القيمة هي كل حالة والإرسال .


الآن ، لنفترض أن لدينا مكون AppHeader يحتوي على زر تسجيل الدخول / الخروج.


 // AppHeader.jsx import React, {useCallback} from "react"; import { useStore } from "./store/useStore"; const AppHeader = props => { const { state, dispatch } = useStore(); const login = useCallback(() => dispatch({ type: "login" }), [dispatch]); const logout = useCallback(() => dispatch({ type: "logout" }), [dispatch]); const handleClick = () => { loggedIn ? logout() : login(); } return ( <div> <button onClick={handleClick}> {loggedIn ? "Logout" : "Login"}</button> <span>{state.user.loggedIn ? "logged in" : "logged out"}</span> <span>Counter: {state.count}</span> </div> ); }; export default AppHeader; 

رابط إلى Sandbox Code مع التنفيذ الكامل


المؤلف الأصلي: رامزي
رابط إلى الأصل

Source: https://habr.com/ru/post/ar460083/


All Articles