为什么我的React Hook不起作用?它以错误的值重新加载

时间:2019-10-13 17:31:19

标签: javascript reactjs react-hooks

这是实时示例代码https://codesandbox.io/embed/wonderful-moon-sc9o2

我想实现某种i18n(例如react-i18next

当我单击“更改语言”按钮时,我希望所有不同组件的翻译都得到更新:

document.getElementById(result).innerHTMl = `For a 4 years college degree with Annual cost: $${annualCost} and Inflation rate: ${inflationRate}`
+ `You have to pay $${totalCost}.`
+ `You need to save ${annualSaving} annually for ${yearsUntilCollege} years.`;

我的钩子中的// Example.js // t.ui.btn - is a path to string token // { ui: { btn: 'Change Language' } } <button>{t.ui.btn}</button> 变量已正确更改,但是该钩子不会将更改传播到应用程序。相反,它将呈现初始lang值。

您会注意到lang如何在控制台中接收初始值。

我的钩子怎么了?如何解决?

index.js

lang

Example.js

import React from "react";
import ReactDOM from "react-dom";
import { Example } from "./Example";
import { Header } from "./Header";
import { useTranslation } from "./useTranslation";
import "./styles.css";

function App() {
  const { t } = useTranslation();

  return (
    <div className="App">
      <Header />
      <h3>{t.app.title}</h3>
      <div>
        <Example />
      </div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

useTranslation.js 钩子

import React, { useState } from "react";
import { useTranslation } from "./useTranslation";

function Example() {
  const [count, setCount] = useState({ count: 1 });
  const { t } = useTranslation();

  function onClick(ev) {
    setCount(prevState => ({
      count: ++prevState.count
    }));
  }

  return (
    <div>
      <p>Clicks state: {JSON.stringify(count)}</p>
      <button onClick={onClick}>{t.ui.btn}</button>
    </div>
  );
}

export { Example };

Header.js

import React, { useState, useEffect } from "react";
import { dict as en } from "./en";
import { dict as de } from "./de";

const useTranslation = () => {
  const [lang, setLang] = useState("en");
  const dict = {
    en,
    de
  };

  function changeLang(lang) {
    console.log("[useTranslation][changeLang] lang", lang);
    setLang(lang);
  }

  console.log("[useTranslation] lang", lang);

  return {
    t: dict[lang],
    changeLang: changeLang,
    lang
  };
};

export { useTranslation };

en.js 翻译

import React, { useState } from "react";
import { useTranslation } from "./useTranslation";

function Header() {
  const { changeLang, lang, t } = useTranslation();

  function onChangeLang(ev) {
    console.log("[index][onChangeLang] lang", lang);
    changeLang(lang === "en" ? "de" : "en");
  }

  return (
    <div>
      <button onClick={onChangeLang}>{t.ui.changeLang}</button>&nbsp;
      <span>{lang}</span>
    </div>
  );
}

export { Header };

de.js 翻译

const dict = {
  ui: {
    btn: "COUNT",
    changeLang: "CHANGE LANGUAGE"
  },
  app: {
    title: "Hook Example"
  }
};

export { dict };

1 个答案:

答案 0 :(得分:1)

每次从组件调用挂钩时,都会初始化挂钩。当您从HeaderApp调用同一钩子时,将创建状态lang的两个独立实例。相反,您需要的是React Context,它可以保留各个组件之间的状态。

const LanguageContext = createContext({
  lang: "en",
  setLang: () => {},
});

const LanguageProvider = ({ children }) => {
  const [lang, setLang] = useState("en");
  return (
    <LanguageContext.Provider value={{ lang, setLang }}>
      {children}
    </LanguageContext.Provider>
  )
}

const useTranslation = () => {
  const langContext = useContext(LanguageContext);
  const dict = {
    en,
    de
  };

  return {
    t: dict[langContext.lang],
    lang: langContext.lang,
    changeLang: langContext.setLang,
  };
};

export { useTranslation, LanguageContext, LanguageProvider };

Codesandbox | React Context