Javascript React路由器更改url但不更新上下文

Javascript React路由器更改url但不更新上下文,javascript,reactjs,react-redux,react-router,react-context,Javascript,Reactjs,React Redux,React Router,React Context,我有一个页面模板,其中包含一组不同的键,用于以用户选择的语言显示文本。默认语言为英语,英语页面对应的URL为localhost:3000。用户可以通过单击按钮切换到西班牙语。当用户单击按钮切换到西班牙语时,将调用history.push()函数。它用给定的国家/地区代码更新URL,在这种情况下,URL变成localhost:3000/es。单击浏览器后退按钮时,URL将变回localhost:3000,但视图仍为西班牙语 我与这个问题斗争了一段时间,并尝试实施多种解决方案,其中包括: 使用带路

我有一个页面模板,其中包含一组不同的键,用于以用户选择的语言显示文本。默认语言为英语,英语页面对应的URL为
localhost:3000
。用户可以通过单击按钮切换到西班牙语。当用户单击按钮切换到西班牙语时,将调用
history.push()
函数。它用给定的国家/地区代码更新URL,在这种情况下,URL变成
localhost:3000/es
。单击浏览器后退按钮时,URL将变回
localhost:3000
,但视图仍为西班牙语

我与这个问题斗争了一段时间,并尝试实施多种解决方案,其中包括:

  • 使用带路由器的
    组件包装组件
    
  • 使用
    路由器
    组件将历史对象作为道具传递
  • 使用
    componentdiddupdate
    强制更新组件
  • 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'));
App
组件包含翻译键,如下所示

//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.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;
//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在改变,但组件保持原样。如果有人能帮我把我推向正确的方向,我们将不胜感激。

使用react-dev工具检查组件的道具和状态-无更改,无需重新招标

您的减速机适用于“事件”。。。更改url(后退按钮)会导致道具更改,而不是动作分派

使用状态,而不是道具-道具更改时保持不变,无需重新播放


只需检查道具并更新渲染函数,使其能够感知道具的更改。

将您的语言值添加到basename道具到
组件,它将为您的所有路线创建一个基本路径

const appRoutes=props=>(
);
如果语言为英语,则您的URL将为:

localhost:3000/en

对于您拥有的其他语言,basename也不会更改。由用户使用推送功能。

您能再解释一下吗?如何利用语言的价值,以及在用户单击浏览器后退按钮后添加基本名称如何更新组件?无需检查后退按钮,您只需将应用程序组件连接到应用商店即可获取所选语言,并将其作为基本名称添加到BrowserRoute组件中。将我的代码更改为
时,会抛出错误
TypeError:Cannot read property edit_and_save of undefined
引用
languageHandler.js
中的
getTranslate()