Mam ustawienia języka w kontekście jak poniżej
class LanguageProvider extends Component {
static childContextTypes = {
langConfig: PropTypes.object,
};
getChildContext() {
return { langConfig: 'en' };
}
render() {
return this.props.children;
}
}
export default LanguageProvider;
Mój kod aplikacji będzie wyglądał jak poniżej
<LanguageProvider>
<App>
<MyPage />
</App>
</LanguageProvider>
Moja strona zawiera komponent do zmiany języka
<MyPage>
<LanguageSwitcher/>
</MyPage>
LanguageSwitcher
w tym MyPage
celu należy zaktualizować kontekst, aby zmienić język na „jp”, jak poniżej
class LanguageSwitcher extends Component {
static contextTypes = {
langConfig: PropTypes.object,
};
updateLanguage() {
//Here I need to update the langConfig to 'jp'
}
render() {
return <button onClick={this.updateLanguage}>Change Language</button>;
}
}
export default LanguageSwitcher;
Jak mogę zaktualizować kontekst z poziomu komponentu LanguageSwitcher?
javascript
reactjs
react-context
mshameer
źródło
źródło
Odpowiedzi:
Korzystanie z haków
Hooki zostały wprowadzone w 16.8.0, więc poniższy kod wymaga minimalnej wersji 16.8.0 (przewiń w dół, aby zobaczyć przykład komponentów klas). CodeSandbox Demo
1. Ustawienie stanu nadrzędnego dla dynamicznego kontekstu
Po pierwsze, aby mieć dynamiczny kontekst, który można przekazać konsumentom, użyję stanu rodzica. Gwarantuje to, że mam jedno źródło prawdy. Na przykład moja aplikacja nadrzędna będzie wyglądać następująco:
const App = () => { const [language, setLanguage] = useState("en"); const value = { language, setLanguage }; return ( ... ); };
language
Jest przechowywana w państwie. Później przekażemy obielanguage
funkcje i funkcję ustawiającąsetLanguage
przez kontekst.2. Tworzenie kontekstu
Następnie stworzyłem taki kontekst językowy:
// set the defaults const LanguageContext = React.createContext({ language: "en", setLanguage: () => {} });
Tutaj ustawiam wartości domyślne dla
language
(„en”) isetLanguage
funkcję, która zostanie wysłana przez dostawcę kontekstu do konsumenta (ów). Są to tylko wartości domyślne i podam ich wartości, gdy używam komponentu dostawcy w obiekcie nadrzędnymApp
.Uwaga:
LanguageContext
pozostaje to samo, niezależnie od tego, czy używasz haków, czy komponentów opartych na klasach.3. Stworzenie konsumenta kontekstowego
Aby przełącznik języka ustawiał język, powinien mieć dostęp do funkcji ustawiania języka poprzez kontekst. Może wyglądać mniej więcej tak:
const LanguageSwitcher = () => { const { language, setLanguage } = useContext(LanguageContext); return ( <button onClick={() => setLanguage("jp")}> Switch Language (Current: {language}) </button> ); };
Tutaj ustawiam język na „jp”, ale możesz mieć własną logikę, aby ustawić języki.
4. Owinięcie konsumenta w dostawcę
Teraz wyrenderuję mój komponent do przełączania języków w a
LanguageContext.Provider
i przekażę wartości, które muszą być wysłane przez kontekst do dowolnego poziomu głębiej. Oto jak wygląda mój rodzicApp
:const App = () => { const [language, setLanguage] = useState("en"); const value = { language, setLanguage }; return ( <LanguageContext.Provider value={value}> <h2>Current Language: {language}</h2> <p>Click button to change to jp</p> <div> {/* Can be nested */} <LanguageSwitcher /> </div> </LanguageContext.Provider> ); };
Teraz po każdym kliknięciu przełącznika języka dynamicznie aktualizuje on kontekst.
CodeSandbox Demo
Korzystanie z komponentów klas
Najnowsze API kontekstowe zostało wprowadzone w React 16.3, co zapewnia doskonały sposób na posiadanie dynamicznego kontekstu. Poniższy kod wymaga minimalnej wersji 16.3.0. CodeSandbox Demo
1. Ustawienie stanu nadrzędnego dla dynamicznego kontekstu
Po pierwsze, aby mieć dynamiczny kontekst, który można przekazać konsumentom, użyję stanu rodzica. Gwarantuje to, że mam jedno źródło prawdy. Na przykład moja aplikacja nadrzędna będzie wyglądać następująco:
class App extends Component { setLanguage = language => { this.setState({ language }); }; state = { language: "en", setLanguage: this.setLanguage }; ... }
Plik
language
on przechowywany w stanie wraz z metodą ustawiania języka, którą można trzymać poza drzewem stanu.2. Tworzenie kontekstu
Następnie stworzyłem taki kontekst językowy:
// set the defaults const LanguageContext = React.createContext({ language: "en", setLanguage: () => {} });
Tutaj ustawiam wartości domyślne dla
language
(„en”) isetLanguage
funkcję, która zostanie wysłana przez dostawcę kontekstu do konsumenta (ów). Są to tylko wartości domyślne i podam ich wartości, gdy używam komponentu dostawcy w obiekcie nadrzędnymApp
.3. Stworzenie konsumenta kontekstowego
Aby przełącznik języka ustawiał język, powinien mieć dostęp do funkcji ustawiania języka poprzez kontekst. Może wyglądać mniej więcej tak:
class LanguageSwitcher extends Component { render() { return ( <LanguageContext.Consumer> {({ language, setLanguage }) => ( <button onClick={() => setLanguage("jp")}> Switch Language (Current: {language}) </button> )} </LanguageContext.Consumer> ); } }
Tutaj ustawiam język na „jp”, ale możesz mieć własną logikę, aby ustawić języki.
4. Owinięcie konsumenta w dostawcę
Teraz wyrenderuję mój komponent do przełączania języków w a
LanguageContext.Provider
i przekażę wartości, które muszą być wysłane przez kontekst do dowolnego poziomu głębiej. Oto jak wygląda mój rodzicApp
:class App extends Component { setLanguage = language => { this.setState({ language }); }; state = { language: "en", setLanguage: this.setLanguage }; render() { return ( <LanguageContext.Provider value={this.state}> <h2>Current Language: {this.state.language}</h2> <p>Click button to change to jp</p> <div> {/* Can be nested */} <LanguageSwitcher /> </div> </LanguageContext.Provider> ); } }
Teraz po każdym kliknięciu przełącznika języka dynamicznie aktualizuje on kontekst.
CodeSandbox Demo
źródło
Provider
?value
, konsument użyje ustawień domyślnych.setLanguage: (language: string) => {}
pracuje dla mnie.Powyższa odpowiedź Maithani to świetne rozwiązanie, ale jest to element klasy bez użycia haczyków. Ponieważ React zaleca używanie komponentów funkcjonalnych i hooków, więc zaimplementuję to z hookami useContext i useState. Oto jak zaktualizować kontekst z poziomu komponentu potomnego.
LanguageContextMangement.js
import React, { useState } from 'react' export const LanguageContext = React.createContext({ language: "en", setLanguage: () => {} }) export const LanguageContextProvider = (props) => { const setLanguage = (language) => { setState({...state, language: language}) } const initState = { language: "en", setLanguage: setLanguage } const [state, setState] = useState(initState) return ( <LanguageContext.Provider value={state}> {props.children} </LanguageContext.Provider> ) }
App.js
import React, { useContext } from 'react' import { LanguageContextProvider, LanguageContext } from './LanguageContextManagement' function App() { const state = useContext(LanguageContext) return ( <LanguageContextProvider> <button onClick={() => state.setLanguage('pk')}> Current Language is: {state.language} </button> </LanguageContextProvider> ) } export default App
źródło
() => {}
state.setLanguage('pk')
nic nie zrobię, ponieważconst state = useContext(LanguageContext)
znajduje się pozaLanguageContextProvider
. Rozwiązałem swój problem, przenosząc dostawcę o jeden poziom w górę, a następnie używającuseContext
u dziecka o jeden poziom niżej.<LanguageContext.Consumer> {value => /* access your value here */} </LanguageContext.Consumer>
.Jednym dość prostym rozwiązaniem jest ustawienie stanu w kontekście przez dołączenie metody setState do dostawcy w następujący sposób:
return ( <Context.Provider value={{ state: this.state, updateLanguage: (returnVal) => { this.setState({ language: returnVal }) } }}> {this.props.children} </Context.Provider> )
A w swoim kliencie zadzwoń do updateLanguage, takiego jak:
// button that sets language config <Context.Consumer> {(context) => <button onClick={context.updateLanguage({language})}> Set to {language} // if you have a dynamic val for language </button> <Context.Consumer>
źródło