การทำงานกับ React Context API

เผยแพร่แล้ว: 2022-03-11

React Context API เป็นฟีเจอร์ทดลองมาระยะหนึ่งแล้ว แต่เฉพาะในเวอร์ชัน 16.3.0 ของ React เท่านั้นที่ปลอดภัยที่จะใช้ในการผลิต บทความด้านล่างจะแสดงแอปร้านค้าบนเว็บพื้นฐานสองแอป แอปหนึ่งสร้างด้วย Context API และอีกแอปหนึ่งไม่มีแอป

API ใหม่นี้แก้ปัญหาสำคัญอย่างหนึ่ง – การเจาะเสา แม้ว่าคุณจะไม่คุ้นเคยกับคำศัพท์นี้ แต่หากคุณเคยทำงานในแอพ React.js มันอาจจะเกิดขึ้นกับคุณ การเจาะเสาคือการประมวลผลการรับข้อมูลจากส่วนประกอบ A ไปยังส่วนประกอบ Z โดยการส่งผ่านส่วนประกอบ React ตัวกลางหลายชั้น ส่วนประกอบจะได้รับอุปกรณ์ประกอบฉากทางอ้อม และ คุณ ผู้พัฒนา React จะต้องตรวจสอบให้แน่ใจว่าทุกอย่างถูกต้อง

มาสำรวจว่าคุณจะจัดการกับปัญหาทั่วไปอย่างไรโดยไม่มี React Context API

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> ); } }

รายการสินค้า .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> );

จริงอยู่ นี่ไม่ใช่วิธีที่ดีที่สุดในการจัดการข้อมูลของคุณ แต่ฉันหวังว่าสิ่งนี้จะแสดงให้เห็นว่าเหตุใด การเจาะเสาจึงดูด Context API จะช่วยเราหลีกเลี่ยงสิ่งนี้ได้อย่างไร

ขอแนะนำ Context Web Store

มาปรับโครงสร้างแอปใหม่และแสดงให้เห็นว่าแอปทำอะไรได้บ้าง พูดได้สั้นๆ ว่า Context API ช่วยให้คุณมีร้านค้ากลางที่มีข้อมูลของคุณอยู่ (ใช่ เหมือนกับใน Redux) ร้านค้าสามารถแทรกลงในส่วนประกอบใด ๆ ได้โดยตรง ตัดพ่อค้าคนกลางออกได้!

ตัวอย่างของกระแสสองสถานะ: หนึ่งกับ React Context API และอีกอันที่ไม่มี

การปรับโครงสร้างใหม่ทำได้ง่ายมาก เราไม่ต้องทำการเปลี่ยนแปลงวิธีจัดโครงสร้างส่วนประกอบใดๆ อย่างไรก็ตาม เราจำเป็นต้องสร้างส่วนประกอบใหม่ ทั้งผู้ให้บริการและผู้บริโภค

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 ในนั้น เราเริ่มต้นสถานะด้วยค่าบางอย่าง ซึ่งคุณสามารถแบ่งปันผ่าน ค่า prop ส่วนประกอบผู้ให้บริการของเรา ในตัวอย่างของเรา เรากำลังแบ่งปัน 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 และ Context API เล็กน้อย ข้อได้เปรียบที่ใหญ่ที่สุดอย่างหนึ่งของ Redux คือความจริงที่ว่าแอปของคุณสามารถมีร้านค้ากลางซึ่งสามารถเข้าถึงได้จากส่วนประกอบใดก็ได้ ด้วย Context API ใหม่ คุณจะมีฟังก์ชันดังกล่าวโดยค่าเริ่มต้น มีการโฆษณาจำนวนมากที่ Context API จะทำให้ Redux ล้าสมัย

นี่อาจเป็นจริงสำหรับผู้ที่ใช้ Redux สำหรับความสามารถของ Central Store เท่านั้น หากนั่นเป็นคุณสมบัติเดียวที่คุณใช้อยู่ คุณสามารถแทนที่ด้วย Context API และหลีกเลี่ยงการเจาะอุปกรณ์โดยไม่ต้องใช้ไลบรารีของบุคคลที่สาม

หากคุณสนใจในการวัดและเพิ่มประสิทธิภาพการทำงานของแอปพลิเคชัน React ของคุณ โปรดอ่าน คำแนะนำในการเพิ่มประสิทธิภาพปฏิกิริยาตอบสนอง โดยเพื่อน Toptaler William Wang