يتم استخدام
الحالة لتنظيم مراقبة البيانات من تطبيقات React. تتغير الدول عندما يتفاعل المستخدمون مع التطبيقات. عندما ينفذ المستخدم بعض الإجراءات ، نحتاج إلى تحديث الحالة ، وهي عبارة عن مجموعة من البيانات على أساس تشكيل ما يراه المستخدم على الشاشة. قم بتحديث حالة تطبيقات
React باستخدام طريقة
setState .

بما أنه لا ينبغي تحديث الولايات مباشرة (في React ، يجب أن تكون الحالة غير قابلة للتغيير) ، مع تعقيد بنية الحالات ، يتحول العمل معها إلى مهمة غير تافهة للغاية. وهي ، يصعب على المبرمج التنقل في الولاية واستخدام بياناته في التطبيق.
في مثل هذه الحالات ، يمكنك استخدام مكتبة Immer. استخدامه في تطبيقات React مخصص للمادة ، التي ننشر ترجمتها اليوم.
أساسيات استخدام Immer في تطبيقات React
عند استخدام Immer ، يمكن تبسيط بنية حالة تطبيق React ، مما يعني أنه سيكون من الأسهل التعامل معه. يستخدم إيمير مفهوم ما يسمى "المسودة". يمكن أخذ "مسودة" كنسخة من الدولة ، ولكن ليس كدولة واحدة.
يقوم Immer ، كما كان ، بنسخ الحالة عن طريق "الضغط" على مفاتيح CMD + C ، ثم ، باستخدام مفاتيح CMD + V ، يدرج ما نسخه في مكان يمكن فيه عرض البيانات المنسوخة دون إزعاج المواد الأصلية. يتم تغيير البيانات المضمنة في الحالة في "المسودة" ، وبعد ذلك ، بناءً على التغييرات التي تم إجراؤها على "المسودة" ، يتم تحديث الحالة الحالية للتطبيق.
لنفترض أن حالة التطبيق تبدو كما يلي:
this.state = { name: 'Kunle', age: 30, city: 'Lagos', country: 'Nigeria' }
هنا هي بيانات المستخدم. هذا المستخدم ، كما اتضح ، يحتفل بعيد ميلاده الحادي والثلاثين. هذا يعني أننا بحاجة إلى تحديث عصره (خاصية
age
). إذا كنت تستخدم Immer لحل هذه المشكلة ، فسيتم إنشاء نسخة من هذه الحالة أولاً.
الآن تخيل أنه تم صنع نسخة من الثروة ، وتم تسليمها إلى حامل الحقيبة ، وقام بتسليم هذه النسخة إلى Kunle. وهذا يعني أن هناك الآن نسختين من الدولة. أحدها هو الحالة الحالية للتطبيق ، والثاني هو نسخة "تقريبية" تم نقلها إلى المستخدم. يقوم المستخدم ، الذي يقوم بتحرير "المسودة" ، بتغيير عمره إلى 31 عامًا. وبعد ذلك ، يعود الساعي مع المستند الذي تم تغييره ويعطي "المسودة" للتطبيق. هناك ، يتم إجراء مقارنة بين نسختين من المستند ويتم إجراء التغييرات المتعلقة بعمر المستخدم فقط على الحالة الحالية للتطبيق ، حيث لم يتغير أي شيء في المسودة.
مخطط العمل هذا لا ينتهك فكرة حصانة الدولة - الحالة الحالية لا يتم تحديثها مباشرة. بشكل عام ، يمكننا القول أن استخدام Immer يساعد ببساطة في تحسين قابلية استخدام الحالة المناعية.
مثال رقم 1: إشارة المرور
دعنا نلقي نظرة على مثال تطبيق يعمل يستخدم Immer. افترض أنك تقوم بتطوير تطبيق إشارة المرور. في هذا التطبيق ، يمكنك محاولة استخدام Immer.
إليك ما تبدو عليه شاشة هذا التطبيق في إحدى لحظات تشغيله.
تطبيق إشارة المرورهنا يمكنك العثور على رمز المشروع.
إليك الشكل الذي سيبدو عليه المكون ، نظرًا لأن المشروع يستخدم Immer.
const {produce} = immer class App extends React.Component { state = { red: 'red', yellow: 'black', green: 'black', next: "yellow" } componentDidMount() { this.interval = setInterval(() => this.changeHandle(), 3000); } componentWillUnmount() { clearInterval(this.interval); } handleRedLight = () => { this.setState( produce(draft => { draft.red = 'red'; draft.yellow = 'black'; draft.green = 'black'; draft.next = 'yellow' }) ) } handleYellowLight = () => { this.setState( produce(draft => { draft.red = 'black'; draft.yellow = 'yellow'; draft.green = 'black'; draft.next = 'green' }) ) } handleGreenLight = () => { this.setState( produce(draft => { draft.red = 'black'; draft.yellow = 'black'; draft.green = 'green'; draft.next = 'red' }) ) } changeHandle = () => { if (this.state.next === 'yellow') { this.handleYellowLight() } else if (this.state.next === 'green') { this.handleGreenLight() } else { this.handleRedLight() } } render() { return ( <div className="box"> <div className="circle" style={{backgroundColor: this.state.red}}></div> <div className="circle" style={{backgroundColor: this.state.yellow}}></div> <div className="circle" style={{backgroundColor: this.state.green}}></div> </div> ); } };
تعد ميزة الإنتاج ميزة قياسية مستوردة من Immer.
setState()
، كقيمة ، إلى طريقة
setState()
. تأخذ دالة
produce
وظيفة ، كحجة ، تأخذ
draft
. ضمن هذه الوظيفة ، يمكننا تعديل حالة "المسودة" ، بحيث نصلها إلى الشكل الذي يجب أن يأخذ حالة حقيقية.
إذا كان كل هذا يبدو معقدًا جدًا لك - فإليك طريقة أخرى لكتابة التعليمات البرمجية التي تحل نفس المهام مثل الكود أعلاه. أولاً ، قم بإنشاء وظيفة:
const handleLight = (state) => { return produce(state, (draft) => { draft.red = 'black'; draft.yellow = 'black'; draft.green = 'green'; draft.next = 'red' }); }
إلى دالة
produce
، نحن ، كوسائط ، نمرر حالة التطبيق الحالية ووظيفة أخرى تأخذ
draft
الوسيطة. الآن دعونا نستفيد من كل هذا في المكون:
handleGreenLight = () => { const nextState = handleLight(this.state) this.setState(nextState) }
مثال 2: قائمة التسوق
إذا كنت تعمل مع React لبعض الوقت ، فيجب ألا تفاجأ من
صيغة الانتشار . عند استخدام Immer ، لن تحتاج إلى استخدام تصميمات مماثلة. على وجه الخصوص ، عند العمل مع المصفوفات الواردة في الدولة.
سنستمر في استكشاف إمكانيات Immer ، وإنشاء تطبيق يقوم بتطبيق قائمة التسوق.
قائمة التسوقهنا يمكنك تجربة ذلك.
هنا هو المكون الذي نعمل معه.
class App extends React.Component { constructor(props) { super(props) this.state = { item: "", price: 0, list: [ { id: 1, name: "Cereals", price: 12 }, { id: 2, name: "Rice", price: 10 } ] } } handleInputChange = e => { this.setState( produce(draft => { draft[event.target.name] = event.target.value })) } handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuid.v4(), name: this.state.name, price: this.state.price } this.setState( produce(draft => { draft.list = draft.list.concat(newItem) }) ) }; render() { return ( <React.Fragment> <section className="section"> <div className="box"> <form onSubmit={this.handleSubmit}> <h2>Create your shopping list</h2> <div> <input type="text" placeholder="Item's Name" onChange={this.handleInputChange} name="name" className="input" /> </div> <div> <input type="number" placeholder="Item's Price" onChange={this.handleInputChange} name="price" className="input" /> </div> <button className="button is-grey">Submit</button> </form> </div> <div className="box"> { this.state.list.length ? ( this.state.list.map(item => ( <ul> <li key={item.id}> <p>{item.name}</p> <p>${item.price}</p> </li> <hr /> </ul> )) ) : <p>Your list is empty</p> } </div> </section> </React.Fragment> ) } } ReactDOM.render( <App />, document.getElementById('root') );
عند إضافة ملاحظات تسوق جديدة إلى القائمة ، نحتاج إلى تحديث حالة المكون الذي ينبغي في عناصر القائمة حفظ العناصر الجديدة فيه. لتحديث عنصر
list
باستخدام طريقة
setState()
، تحتاج إلى الكود التالي:
handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuid.v4(), name: this.state.name, price: this.state.price } this.setState({ list: [...this.state.list, newItem] }) };
إذا كنت بحاجة إلى تحديث الكثير من عناصر الحالة أثناء تشغيل التطبيق - فسيتعين استخدام بناء جملة الانتشار كثيرًا. يتم الحصول على حالة جديدة من خلال دمج ما هو موجود بالفعل في الولاية مع بيانات جديدة. كلما زاد عدد التغييرات ، يصبح العمل أكثر تعقيدًا. إذا كنت تستخدم Immer - مثل هذه الأشياء لا تسبب صعوبات. يمكنك التحقق من ذلك من خلال النظر في رمز المثال في بداية هذا القسم.
ولكن ماذا لو أردنا إضافة وظيفة إلى المشروع ، في شكل رد اتصال ، سيتم استدعاؤها بعد تحديث الحالة؟ على سبيل المثال ، قد يكون ذلك ضروريًا إذا كنت بحاجة إلى حساب عدد الإدخالات في القائمة أو التكلفة الإجمالية لجميع المشتريات المخطط لها.
هنا يمكنك إلقاء نظرة على رمز التطبيق ، والذي سنقوم بتحليله الآن. هو مبين أدناه واجهة.
التطبيق مع وظيفة حساب التكلفة الإجمالية للمشتريات المخطط لهالذلك ، لنفترض أننا نريد حساب القيمة الإجمالية لعمليات الشراء المخططة. لنبدأ بإنشاء آلية تحديث الحالة. يتم تمثيل هذه الآلية بواسطة الدالة
handleSubmit
:
handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuid.v4(), name: this.state.name, price: this.state.price } this.setState( produce(draft => { draft.list = draft.list.concat(newItem) }), () => { this.calculateAmount(this.state.list) } ) };
في دالة
handleSubmit
نقوم أولاً بإنشاء كائن بناءً على البيانات التي أدخلها المستخدم. تتم كتابة المرجع إلى الكائن
newItem
ثابت. لتكوين حالة جديدة للتطبيق ، يتم استخدام طريقة
.concat()
. تُرجع هذه الطريقة ، التي تسمى المصفوفة ، صفيفًا جديدًا ، يتضمن عناصر من المصفوفة الأصلية ، بالإضافة إلى عنصر جديد. الصفيف الجديد مكتوب إلى
draft.list
. بعد ذلك ، يمكن لـ Immer تحديث حالة التطبيق.
يتم استدعاء رد الاتصال ، وظيفة
calculateAmount
، بعد تحديث الحالة. من المهم ملاحظة أن هذه الوظيفة تستخدم إصدارًا محدثًا من الحالة.
ستبدو وظيفة
calculateAmount
بالشكل التالي:
calculateAmount = (list) => { let total = 0; for (let i = 0; i < list.length; i++) { total += parseInt(list[i].price, 10) } this.setState( produce(draft => { draft.totalAmount = total }) ) }
السنانير immer
Use-immer هو خطاف يسمح للمطور بالتحكم في حالة تطبيقات React. دعونا نلقي نظرة على كيفية عمل هذا الخطاف من خلال تطبيق التطبيق المضاد الكلاسيكي على أساسه:
import React from "react"; import {useImmer} from "use-immer"; const Counter = () => { const [count, updateCounter] = useImmer({ value: 0 }); function increment() { updateCounter(draft => { draft.value = draft.value +1; }); } return ( <div> <h1> Counter {count.value} </h1> <br /> <button onClick={increment}>Increment</button> </div> ); } export default Counter;
useImmer
وظيفة
useImmer طريقة
useState . تقوم الدالة بإرجاع حالة والدالة التي تقوم بتحديث الحالة. عند تحميل المكون لأول مرة ، تتوافق محتويات الحالة (في هذه الحالة ، خاصية
count
) مع القيمة التي تم تمريرها إلى
useImmer
. يتيح لنا استخدام الوظيفة التي تم إرجاعها لتحديث الحالة إنشاء وظيفة زيادة تزيد من قيمة خاصية حالة
count
.
وهنا الكود الذي يستخدم الخطاف لـ Immer ، يذكرنا
useReducer :
import React, { useRef } from "react"; import {useImmerReducer } from "use-immer"; import uuidv4 from "uuid/v4" const initialState = []; const reducer = (draft, action) => { switch (action.type) { case "ADD_ITEM": draft.push(action.item); return; case "CLEAR_LIST": return initialState; default: return draft; } } const Todo = () => { const inputEl = useRef(null); const [state, dispatch] = useImmerReducer(reducer, initialState); const handleSubmit = (e) => { e.preventDefault() const newItem = { id: uuidv4(), text: inputEl.current.value }; dispatch({ type: "ADD_ITEM", item: newItem }); inputEl.current.value = ""; inputEl.current.focus(); } const handleClear = () => { dispatch({ type: 'CLEAR_LIST' }) } return ( <div className='App'> <header className='App-header'> <ul> {state.map(todo => { return <li key={todo.id}>{todo.text}</li>; })} </ul> <form onSubmit={handleSubmit}> <input type='text' ref={inputEl} /> <button type='submit' > Add Todo </button> </form> <button onClick={handleClear} > Clear Todos </button> </header> </div> ); } export default Todo;
تقبل الدالة
useImmerReducer
وظيفة
useImmerReducer
والحالة الأولية. تقوم بإرجاع وظيفة الدولة
dispatch
. بعد ذلك ، يمكنك تجاوز الحالة لعرض العناصر الموجودة فيها. يتم تنفيذ إجراءات الإرسال باستخدام وظيفة
dispatch
عندما تتم إضافة عنصر جديد إلى قائمة المهام وعندما يتم مسح القائمة. يتم تعيين الإجراء المراد إرساله بناءً على القرار الذي يتم اتخاذه في وظيفة المخفض حول ما يجب القيام به بالضبط لمعالجة إجراء معين.
في المخفض ، نستخدم ، كما كان من قبل ، كيان
draft
، وليس
state
. بفضل هذا ، لدينا وسيلة مريحة لإدارة حالة التطبيق.
يمكن العثور على الكود المستخدم في المثال السابق
هنا .
النتائج
في هذه المقالة ، تحدثنا عن Immer ، وهي مكتبة تبسط إدارة حالة تطبيقات React. يعتقد مؤلف المقال أن كل شخص مهتم بهذه المكتبة قد يستخدم Immer جيدًا في تطبيقاته الجديدة أو يعرّفها ببطء في أحد المشاريع الحالية.
فيما يلي المواد التي يمكنك من خلالها العثور على بعض التفاصيل حول Immer.
أعزائي القراء! هل تخطط لاستخدام Immer؟
