العمل مع React Context API

نشرت: 2022-03-11

كانت واجهة برمجة تطبيقات سياق React موجودة كميزة تجريبية لفترة من الوقت الآن ، ولكن فقط في الإصدار 16.3.0 من React أصبحت آمنة للاستخدام في الإنتاج. ستوضح لك المقالة أدناه تطبيقين أساسيين لمتجر الويب ، أحدهما تم إنشاؤه باستخدام واجهة برمجة تطبيقات السياق والآخر بدونه.

تعمل واجهة برمجة التطبيقات الجديدة هذه على حل مشكلة رئيسية واحدة وهي حفر الدعامة . حتى إذا لم تكن معتادًا على المصطلح ، إذا كنت قد عملت على تطبيق React.js ، فمن المحتمل أنه حدث لك. حفر الدعامة هو معالجة إحضار البيانات من المكون A إلى المكون Z عن طريق تمريرها عبر طبقات متعددة من مكونات React الوسيطة. سيتلقى المكون الدعائم بشكل غير مباشر وسيتعين عليك ، على مطور React ، التأكد من أن كل شيء يعمل بشكل صحيح.

دعنا نستكشف كيف ستتعامل مع المشكلات الشائعة بدون واجهة برمجة تطبيقات سياق React ،

App.js

 class App extends Component { state = { cars: { car001: { name: 'Honda', price: 100 }, car002: { name: 'BMW', price: 150 }, car003: { name: 'Mercedes', price: 200 } } }; incrementCarPrice = this.incrementCarPrice.bind(this); decrementCarPrice = this.decrementCarPrice.bind(this); incrementCarPrice(selectedID) { // a simple method that manipulates the state const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price + 1; this.setState({ cars }); } decrementCarPrice(selectedID) { // a simple method that manipulates the state const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price - 1; this.setState({ cars }); } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to my web store</h1> </header> {/* Pass props twice */} <ProductList cars={this.state.cars} incrementCarPrice={this.incrementCarPrice} decrementCarPrice={this.decrementCarPrice} /> </div> ); } }

ProductList .js

 const ProductList = props => ( <div className="product-list"> <h2>Product list:</h2> {/* Pass props twice */} <Cars cars={props.cars} incrementCarPrice={props.incrementCarPrice} decrementCarPrice={props.decrementCarPrice} /> {/* Other potential product categories which we will skip for this demo: */} {/* <Electronics /> */} {/* <Clothes /> */} {/* <Shoes /> */} </div> ); export default ProductList;

Cars.js

 const Cars = props => ( <Fragment> <h4>Cars:</h4> {/* Finally we can use data */} {Object.keys(props.cars).map(carID => ( <Car key={carID} name={props.cars[carID].name} price={props.cars[carID].price} incrementPrice={() => props.incrementCarPrice(carID)} decrementPrice={() => props.decrementCarPrice(carID)} /> ))} </Fragment> );

سيارة. js

 const Cars = props => ( <Fragment> <p>Name: {props.name}</p> <p>Price: ${props.price}</p> <button onClick={props.incrementPrice}>&uarr;</button> <button onClick={props.decrementPrice}>&darr;</button> </Fragment> );

منحت ، هذه ليست أفضل طريقة للتعامل مع بياناتك ، لكنني آمل أن توضح سبب سوء حفر الدعامة . فكيف يمكن لواجهة برمجة تطبيقات السياق مساعدتنا في تجنب ذلك؟

تقديم متجر ويب السياق

دعنا نعيد صياغة التطبيق ونوضح ما يمكنه فعله. باختصار ، تتيح لك واجهة برمجة تطبيقات السياق أن يكون لديك متجر مركزي حيث توجد بياناتك (نعم ، تمامًا كما هو الحال في Redux). يمكن إدخال المخزن في أي مكون مباشرة. يمكنك قطع الوسيط!

مثال على تدفقات حالتين: الأولى باستخدام واجهة برمجة تطبيقات سياق React ، والأخرى بدون

إعادة الهيكلة سهلة للغاية - ليس علينا إجراء أي تغييرات على كيفية هيكلة المكونات. نحن بحاجة إلى إنشاء بعض المكونات الجديدة - مزود ومستهلك.

1. تهيئة السياق

أولاً ، نحتاج إلى إنشاء السياق ، والذي يمكننا استخدامه لاحقًا لإنشاء مقدمي الخدمات والمستهلكين.

MyContext.js

 import React from 'react'; // this is the equivalent to the createStore method of Redux // https://redux.js.org/api/createstore const MyContext = React.createContext(); export default MyContext;

2. إنشاء الموفر

بمجرد الانتهاء من ذلك ، يمكننا استيراد السياق واستخدامه لإنشاء مزودنا ، والذي نسميه MyProvider. في ذلك ، نقوم بتهيئة حالة ببعض القيم ، والتي يمكنك مشاركتها عبر مكون المزود الخاص بنا. في مثالنا ، نشارك this.state.cars جنبًا إلى جنب مع طريقتين للتلاعب بالحالة. فكر في هذه الأساليب كمخفضات في Redux.

MyProvider.js

 import MyContext from './MyContext'; class MyProvider extends Component { state = { cars: { car001: { name: 'Honda', price: 100 }, car002: { name: 'BMW', price: 150 }, car003: { name: 'Mercedes', price: 200 } } }; render() { return ( <MyContext.Provider value={{ cars: this.state.cars, incrementPrice: selectedID => { const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price + 1; this.setState({ cars }); }, decrementPrice: selectedID => { const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price - 1; this.setState({ cars }); } }} > {this.props.children} </MyContext.Provider> ); } }

لجعل الموفر في متناول المكونات الأخرى ، نحتاج إلى تغليف تطبيقنا به (نعم ، تمامًا كما هو الحال في Redux). أثناء وجودنا فيه ، يمكننا التخلص من الحالة والأساليب لأنها محددة الآن في MyProvider.js.

App.js

 class App extends Component { render() { return ( <MyProvider> <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to my web store</h1> </header> <ProductList /> </div> </MyProvider> ); } }

3. إنشاء المستهلك

سنحتاج إلى استيراد السياق مرة أخرى ولف المكون الخاص بنا به والذي يقوم بحقن وسيطة السياق في المكون. بعد ذلك ، إنه مستقيم للأمام. أنت تستخدم السياق ، بنفس الطريقة التي تستخدم بها الدعائم . إنها تحمل جميع القيم التي شاركناها في MyProducer ، نحتاج فقط إلى استخدامها!

Cars.js

 const Cars = () => ( <MyContext.Consumer> {context => ( <Fragment> <h4>Cars:</h4> {Object.keys(context.cars).map(carID => ( <Car key={carID} name={context.cars[carID].name} price={context.cars[carID].price} incrementPrice={() => context.incrementPrice(carID)} decrementPrice={() => context.decrementPrice(carID)} /> ))} </Fragment> )} </MyContext.Consumer> );

ماذا نسينا؟ قائمة المنتجات! هذا هو المكان الذي تصبح فيه الفائدة واضحة. نحن لا نمرر أي بيانات أو طرق. تم تبسيط المكون لأنه يحتاج فقط إلى عرض بعض المكونات.

ProductList.js

 const ProductList = () => ( <div className="product-list"> <h2>Product list:</h2> <Cars /> {/* Other potential product categories which we will skip for this demo: */} {/* <Electronics /> */} {/* <Clothes /> */} {/* <Shoes /> */} </div> );

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

قد يكون هذا صحيحًا بالنسبة لأولئك منكم الذين يستخدمون Redux فقط لإمكانيات المتجر المركزي. إذا كانت هذه هي الميزة الوحيدة التي كنت تستخدمها من أجلها ، فيمكنك الآن استبدالها بواجهة برمجة تطبيقات السياق وتجنب التنقل بالدعائم دون استخدام مكتبات الجهات الخارجية.

إذا كنت مهتمًا بقياس أداء تطبيق React وتحسينه ، فاقرأ دليل تحسين أداء التفاعل بواسطة زميلك Toptaler William Wang.