【发布时间】:2020-04-17 16:29:08
【问题描述】:
我有一个页面模板,其中包含一组不同的键,用于以用户选择的语言显示文本。默认语言为英文,英文页面对应的URL为localhost:3000。用户可以选择通过单击按钮切换到西班牙语。当用户单击按钮以切换到西班牙语时,将调用 history.push() 函数。它使用给定的国家代码更新 URL,在这种情况下 URL 变为 localhost:3000/es。单击浏览器后退按钮时,URL 会变回 localhost:3000,但视图仍为西班牙语。
我在这个问题上苦苦挣扎了一段时间,并尝试实施多种解决方案,其中包括:
- 使用
WithRouter组件包装组件; - 使用
Router组件将历史对象作为道具传递; - 使用
componentDidUpdate强制更新组件; -
App组件中的调用调度;
我的index.js 文件包含渲染AppWrapper 组件的路由。 AppWrapper 组件呈现 App 组件,它是 I18nContextProvider 组件的子组件。
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import App from './App';
import { I18nContextProvider, availableTranslationsEnum } from './languages/languageHandler';
const AppWrapper = (language) => (
<I18nContextProvider language={language}>
<App />
</I18nContextProvider>
);
const appRoutes = (
<BrowserRouter>
<Switch>
<Route
path={`/${availableTranslationsEnum.spanish}`}
render={() => AppWrapper(availableTranslationsEnum.spanish)}
exact
/>
<Route
render={() => AppWrapper(availableTranslationsEnum.english)}
/>
</Switch>
</BrowserRouter>
);
ReactDOM.render(appRoutes, document.getElementById('root'));
I18nContextProvider 组件在 languageHandler.js 文件中定义,如下所示。
//languageHandler.js
import React, { useReducer } from 'react';
import EN from './en.json';
import ES from './es.json';
const translations = {
en: EN,
es: ES,
};
const getTranslate = (langCode) => (key) => translations[langCode][key] || key;
export const availableTranslationsEnum = {
english: Object.keys(translations)[0],
spanish: Object.keys(translations)[1],
};
const setInitialState = (language) => {
const defaultLanguage = availableTranslationsEnum.english;
const siteLanguage = language || defaultLanguage;
return {
langCode: siteLanguage,
translate: getTranslate(siteLanguage),
};
};
export const I18nContext = React.createContext(setInitialState());
export const I18nContextProvider = ({ children, language }) => {
const reducer = (action) => {
switch (action.type) {
case 'setLanguage':
return {
langCode: action.payload,
translate: getTranslate(action.payload),
};
default:
return { ...setInitialState(language) };
}
};
const [state, dispatch] = useReducer(reducer, setInitialState(language));
return (
<I18nContext.Provider value={{ ...state, dispatch }}>
{children}
</I18nContext.Provider>
);
};
App 组件包含翻译键,如下所示。
//App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { I18nContext } from './languages/languageHandler';
import LanguageSelect from './components/LanguageSelect';
const App = () => {
const { translate } = React.useContext(I18nContext);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<LanguageSelect />
<p>
{translate('edit_and_save')}
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
{translate('learn_react')}
</a>
</header>
</div>
);
};
export default App;
App 组件渲染LanguageSelect 组件,看起来像这样。
//LanguageSelect.js
import React, { useContext } from 'react';
import { useHistory } from 'react-router-dom';
import { I18nContext, availableTranslationsEnum } from '../languages/languageHandler';
const LanguageSelect = () => {
const history = useHistory();
const { langCode, dispatch } = useContext(I18nContext);
const switchLanguage = (languageToSwitchTo) => {
const dispatchType = 'setLanguage';
dispatch({ type: dispatchType, payload: languageToSwitchTo });
if (languageToSwitchTo !== availableTranslationsEnum.english) {
history.push(`/${languageToSwitchTo}`);
}
if (languageToSwitchTo === availableTranslationsEnum.english) {
history.push(`/`); //Default language
}
};
if (langCode === availableTranslationsEnum.english) {
return (
<button onClick={() => switchLanguage(availableTranslationsEnum.spanish)}>Español</button>
);
}
return (<button onClick={() => switchLanguage(availableTranslationsEnum.english)}>English</button>);
};
export default LanguageSelect;
我试图了解为什么 URL 发生了变化,但组件保持原样。如果有人可以帮助我将我推向正确的方向,我们将不胜感激。
【问题讨论】:
标签: javascript reactjs react-redux react-router react-context