使用 react-intl 和 mobx 状态树更新语言
Update language using react-intl and mobx state tree
这是我第一次使用 react-intl
和 Mobx state tree
。
基本上我在 header 中有两个按钮(it
和 en
),点击它们可以设置保存在 Mobx 状态树变量中的当前语言。
像这样。
我的状态:
const FULL_LANGUAGE =
(navigator.languages && navigator.languages[0]) || navigator.language || 'en-GB'
const LANGUAGE = FULL_LANGUAGE!.split('-')[0]
export const UIModel = t
.model('UIModel', {
language: LANGUAGE,
})
.actions((self) => ({
setLanguage(language: 'it' | 'en') {
self.language = language
}
}))
在header组件中:
...
<Button textToShow="it" onClick={() => setLanguage('it')} />
<Button textToShow="en" onClick={() => setLanguage('en')} />
...
我的index.tsx
文件:
import React from 'react'
import ReactDOM from 'react-dom'
import { IntlProvider } from 'react-intl'
import { stateInstance, Provider } from './state'
import { App } from './App'
import messagesIt from './locales/messages-it.json5'
import messagesEn from './locales/messages-en.json5'
const language = stateInstance.ui.language
const messages = language === 'en' ? messagesEn : messagesIt
function renderApp() {
ReactDOM.render(
<Provider value={stateInstance}>
<IntlProvider locale={language} messages={messages}>
<App />
</IntlProvider>
</Provider>,
document.getElementById('root')
)
}
renderApp()
和我的 Mobx 状态树根文件:
import { createContext, useContext } from 'react'
import { Instance, types as t } from 'mobx-state-tree'
import { UIModel } from './UI'
export const StateModel = t
.model('StateModel', {
ui: t.optional(UIModel, {}),
})
export const stateInstance = StateModel.create()
export interface StateInstance extends Instance<typeof StateModel> {}
const RootStateContext = createContext<StateInstance | null>(null)
export const Provider = RootStateContext.Provider
export function useMst() {
const state = useContext(RootStateContext)
if (state === null) throw new Error('')
return state
}
问题是,当我单击 it
或 en
按钮时,状态中的语言已更新,但我认为没有任何变化,因为 <IntlProvider locale={language} messages={messages}>
未“重新呈现”。
我该如何解决?
有很多方法可以解决它,例如我认为你可以将 IntlProvider
包装在 Observer
(docs) 组件中以使其具有反应性:
import { Observer } from 'mobx-react';
// ...
function renderApp() {
ReactDOM.render(
<Provider value={stateInstance}>
<Observer>
{() => (
<IntlProvider
locale={stateInstance.ui.language}
messages={
stateInstance.ui.language === 'en' ? messagesEn : messagesIt
}
>
<App />
</IntlProvider>
)}
</Observer>
</Provider>,
document.getElementById('root')
);
}
这样解决了:
const AppContainer: React.FC<{}> = observer(({}) => {
const {
ui: { language },
} = useMst()
return (
<IntlProvider locale={language} messages={language === 'en' ? messagesEn : messagesIt}>
<App />
</IntlProvider>
)
})
function renderApp() {
ReactDOM.render(
<Provider value={stateInstance}>
<AppContainer />
</Provider>,
document.getElementById('root')
)
}
这是我第一次使用 react-intl
和 Mobx state tree
。
基本上我在 header 中有两个按钮(it
和 en
),点击它们可以设置保存在 Mobx 状态树变量中的当前语言。
像这样。
我的状态:
const FULL_LANGUAGE =
(navigator.languages && navigator.languages[0]) || navigator.language || 'en-GB'
const LANGUAGE = FULL_LANGUAGE!.split('-')[0]
export const UIModel = t
.model('UIModel', {
language: LANGUAGE,
})
.actions((self) => ({
setLanguage(language: 'it' | 'en') {
self.language = language
}
}))
在header组件中:
...
<Button textToShow="it" onClick={() => setLanguage('it')} />
<Button textToShow="en" onClick={() => setLanguage('en')} />
...
我的index.tsx
文件:
import React from 'react'
import ReactDOM from 'react-dom'
import { IntlProvider } from 'react-intl'
import { stateInstance, Provider } from './state'
import { App } from './App'
import messagesIt from './locales/messages-it.json5'
import messagesEn from './locales/messages-en.json5'
const language = stateInstance.ui.language
const messages = language === 'en' ? messagesEn : messagesIt
function renderApp() {
ReactDOM.render(
<Provider value={stateInstance}>
<IntlProvider locale={language} messages={messages}>
<App />
</IntlProvider>
</Provider>,
document.getElementById('root')
)
}
renderApp()
和我的 Mobx 状态树根文件:
import { createContext, useContext } from 'react'
import { Instance, types as t } from 'mobx-state-tree'
import { UIModel } from './UI'
export const StateModel = t
.model('StateModel', {
ui: t.optional(UIModel, {}),
})
export const stateInstance = StateModel.create()
export interface StateInstance extends Instance<typeof StateModel> {}
const RootStateContext = createContext<StateInstance | null>(null)
export const Provider = RootStateContext.Provider
export function useMst() {
const state = useContext(RootStateContext)
if (state === null) throw new Error('')
return state
}
问题是,当我单击 it
或 en
按钮时,状态中的语言已更新,但我认为没有任何变化,因为 <IntlProvider locale={language} messages={messages}>
未“重新呈现”。
我该如何解决?
有很多方法可以解决它,例如我认为你可以将 IntlProvider
包装在 Observer
(docs) 组件中以使其具有反应性:
import { Observer } from 'mobx-react';
// ...
function renderApp() {
ReactDOM.render(
<Provider value={stateInstance}>
<Observer>
{() => (
<IntlProvider
locale={stateInstance.ui.language}
messages={
stateInstance.ui.language === 'en' ? messagesEn : messagesIt
}
>
<App />
</IntlProvider>
)}
</Observer>
</Provider>,
document.getElementById('root')
);
}
这样解决了:
const AppContainer: React.FC<{}> = observer(({}) => {
const {
ui: { language },
} = useMst()
return (
<IntlProvider locale={language} messages={language === 'en' ? messagesEn : messagesIt}>
<App />
</IntlProvider>
)
})
function renderApp() {
ReactDOM.render(
<Provider value={stateInstance}>
<AppContainer />
</Provider>,
document.getElementById('root')
)
}