การทำงานกับ React Context API
เผยแพร่แล้ว: 2022-03-11React 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}>↑</button> <button onClick={props.decrementPrice}>↓</button> </Fragment> );
จริงอยู่ นี่ไม่ใช่วิธีที่ดีที่สุดในการจัดการข้อมูลของคุณ แต่ฉันหวังว่าสิ่งนี้จะแสดงให้เห็นว่าเหตุใด การเจาะเสาจึงดูด Context API จะช่วยเราหลีกเลี่ยงสิ่งนี้ได้อย่างไร
ขอแนะนำ Context Web Store
มาปรับโครงสร้างแอปใหม่และแสดงให้เห็นว่าแอปทำอะไรได้บ้าง พูดได้สั้นๆ ว่า Context API ช่วยให้คุณมีร้านค้ากลางที่มีข้อมูลของคุณอยู่ (ใช่ เหมือนกับใน Redux) ร้านค้าสามารถแทรกลงในส่วนประกอบใด ๆ ได้โดยตรง ตัดพ่อค้าคนกลางออกได้!
การปรับโครงสร้างใหม่ทำได้ง่ายมาก เราไม่ต้องทำการเปลี่ยนแปลงวิธีจัดโครงสร้างส่วนประกอบใดๆ อย่างไรก็ตาม เราจำเป็นต้องสร้างส่วนประกอบใหม่ ทั้งผู้ให้บริการและผู้บริโภค
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