React Context API je způsob, jak v podstatě vytvořit globální proměnné, které lze předávat v aplikaci React. Toto je alternativa k „vrtání rekvizit“ nebo předávání rekvizit od prarodičů rodičům k dítěti a tak dále. Kontext je často nabízen jako jednodušší a lehčí řešení pro použití Redux pro správu státu. Sám jsem Redux ještě nepoužil, ale pokaždé, když použiji kontextové API Reactu, musím to vyhledat, protože mi to nepřipadá samozřejmé.
Nechám zde několik stručných a stručných kroků, jak začít s Contextem.
Předpoklad
- Pokud ještě neznáte React nebo React Hooks, přečtěte si článek Začínáme s React nebo Sestavení aplikace React s Hooks.
Vytvořit kontext
Představte si, že mám nějaké informace, které chci být dostupné kdekoli nebo kdekoli v aplikaci React. Motiv lze implementovat pomocí Context – například na tomto webu mám Context, který slouží ke třem tématům:tmavý režim, světlý režim a režim MS-DOS (na stránce 404). V tomto jednoduchém příkladu použiji protokol v uživateli.
Vytvořím kontext a nazvu jej UserContext
. To mi také dá UserContext.Provider
a UserContext.Consumer
. Co tyto dvě složky dělají, je jednoduché:
- Poskytovatel - Komponenta, která poskytuje hodnotu
- Spotřebitel - Komponenta, která spotřebovává hodnotu
Takže to vytvořím pomocí React.createContext()
v novém souboru s názvem UserContext.js
.
import React from 'react'
const UserContext = React.createContext()
export const UserProvider = UserContext.Provider
export const UserConsumer = UserContext.Consumer
export default UserContext
Zde předávám prázdnou hodnotu objektu, abych reprezentoval, že tato data možná vyplním později pomocí volání API. Můžete to předem vyplnit libovolnými údaji, pokud data nenačítáte prostřednictvím rozhraní API.
React.createContext(true)
Poskytování kontextu
Poskytovatel musí vždy existovat jako obal kolem nadřazeného prvku, bez ohledu na to, jak se rozhodnete využívat hodnoty. Zabalím celých App
součást v Provider
. Právě vytvářím nějakou hodnotu (user
) a předat jej jako Provider
hodnota prop.
import React from 'react'
import HomePage from './HomePage'
import { UserProvider } from './UserContext'
function App() {
const user = { name: 'Tania', loggedIn: true }
return (
<UserProvider value={user}>
<HomePage />
</UserProvider>
)
}
Nyní bude mít přístup k user
každé dítě, vnouče, pravnuk a tak dále jako rekvizita. Bohužel získání této hodnoty je o něco složitější než její pouhé získání, jako byste mohli s this.props
nebo this.state
.
Kontext konzumace
Způsob, jakým poskytujete kontext, je stejný pro třídu a funkční komponenty, ale jeho použití je u obou trochu odlišné.
Komponenta třídy
Nejběžnějším způsobem přístupu ke kontextu z komponenty třídy je statický contextType
. Pokud potřebujete hodnotu z kontextu mimo render
, nebo v metodě životního cyklu, budete jej používat tímto způsobem.
import React, { Component } from 'react'
import UserContext from './UserContext'
class HomePage extends Component {
static contextType = UserContext
componentDidMount() {
const user = this.context
console.log(user) // { name: 'Tania', loggedIn: true }
}
render() {
return <div>{user.name}</div>
}
}
Tradičním způsobem, jak získat kontextové hodnoty, bylo zabalení podřízené komponenty do Consumer
. Odtud byste měli mít přístup k hodnotě prop jako props
. Můžete to stále vidět, ale jde spíše o starší způsob přístupu ke kontextu.
import React, { Component } from 'react'
import { UserConsumer } from './UserContext'
class HomePage extends Component {
render() {
return (
<UserConsumer>
{(props) => {
return <div>{props.name}</div>
}}
</UserConsumer>
)
}
}
Funkční komponenta a háčky
Pro funkční komponenty použijete useContext
, jako v příkladu níže. Toto je ekvivalent static contextType
.
import React, { useContext } from 'react'
import UserContext from './UserContext'
export const HomePage = () => {
const user = useContext(UserContext)
return <div>{user.name}</div>
}
Aktualizace kontextu
Aktualizace kontextu se příliš neliší od aktualizace běžného stavu. Můžeme vytvořit obalovou třídu, která obsahuje stav kontextu a prostředky k jeho aktualizaci.
src/UserContext.jsimport React, { Component } from 'react'
const UserContext = React.createContext()
class UserProvider extends Component {
// Context state
state = {
user: {},
}
// Method to update state
setUser = (user) => {
this.setState((prevState) => ({ user }))
}
render() {
const { children } = this.props
const { user } = this.state
const { setUser } = this
return (
<UserContext.Provider
value={{
user,
setUser,
}}
>
{children}
</UserContext.Provider>
)
}
}
export default UserContext
export { UserProvider }
Nyní můžete aktualizovat a zobrazit uživatele pomocí kontextové metody.
import React, { Component } from 'react'
import UserContext from './UserContext'
class HomePage extends Component {
static contextType = UserContext
render() {
const { user, setUser } = this.context
return (
<div>
<button
onClick={() => {
const newUser = { name: 'Joe', loggedIn: true }
setUser(newUser)
}}
>
Update User
</button>
<p>{`Current User: ${user.name}`}</p>
</div>
)
}
}
Podle mého názoru je největší nevýhodou Context API s třídami, že nemůžete použít více statických contextTypes
v jedné složce. To vede k nutnosti mít jeden opravdu velký kontext pro všechny globální stavy v aplikaci, takže pro velkou aplikaci to nestačí. Metoda vytvoření obalu pro Context je také obtížně testovatelná.
Závěr
Abych to shrnul:
- Použijte
const ___Context = React.createContext()
vytvořit kontext. - Zatáhněte za
___Context.Provider
a___Context.Consumer
z___Context
- Zabalit
Provider
kolem vaší nadřazené komponenty. - Třída může spotřebovávat s
static contextType = ___Context
- Funkční komponenta může mít spotřebu
const x = useContext(___Context)
Doufám, že to pomůže!