React-i18next: Components using HOCs are not re-rendered properly since v7.8.0

Created on 22 Jul 2018  路  25Comments  路  Source: i18next/react-i18next

Hi

First of all, thanks a bunch for creating and maintaining this project! I've been really happy with it so far.

Ever since version 7.8.0, with the introduction of omitBoundRerender, I'm having trouble getting my components to re-render on language changes. Passing { omitBoundRerender = false } as options to the Translate HOC solves my problems, but it adds a lot of boilerplate.

Is there a way to set omitBoundRerender as part of the init options?

can not reproduce help wanted

All 25 comments

you can set it on i18n.init

```js
i18n.init({
react: {
omitBoundRerender: false
}
});

That's what I thought, but unfortunately, it doesn't work.

having that setting on init -> does your code return here: https://github.com/i18next/react-i18next/blob/master/src/I18n.js#L100

Hm...do this component not rerender have the wait option set to false? And you set language rather immediately after init -> not a user interaction -> this might be the only edge case i could think of resulting in some weird race condition

Hy guys,

I'm having the same issue here
here is how my i18n.js file looks like:

import Backend from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import i18n from 'i18next';
import { reactI18nextModule } from 'react-i18next';

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(reactI18nextModule)
  .init({
    fallbackLng: 'en',

    ns: ['translations'],
    defaultNS: 'translations',

    debug: true,

    interpolation: {
      escapeValue: false,
    },

    react: {
      wait: false,
      omitBoundRerender: false
    }
  });


export default i18n;

in my navbar I have this function

 const changeLanguage = (lng) => {            
    i18n.changeLanguage(lng);
 }

I have a signupPage which contains translated input fields like such:

<label htmlFor="username" className="col-sm-3 col-form-label">{t('signupForm.username')}</label>

I export the signupform like this

export default compose(
    translate('translations'), 
    connect(mapStateToProps, {submit: createUserRequest})
)(SignupForm);

When I switch locale from any other view everything works fine but when the current view is the login form, the app crashed and I get this error:

TypeError: Cannot read property 'username' of undefined

Any way to fix this?

Why that error should be from i18next....?!?

you must have a access to something.username in your code t('signupForm.username') won't throw an error if signupForm is undefined...

I have this issue as well.

repo: https://github.com/sillsdev/appbuilder-portal/tree/master/source/SIL.AppBuilder.Portal.Frontend

import * as React from 'react';
import * as i18n from 'i18next';
import * as Backend from 'i18next-xhr-backend';
import * as LanguageDetector from 'i18next-browser-languagedetector';
import { reactI18nextModule } from 'react-i18next';

import enUs from './locales/en-us';
import esPe from './locales/es-pe';

const localTranslations = {
  'en-US': { translations: enUs },
};

i18n
  .use(LanguageDetector)
  .init({
    resources: localTranslations,
    fallbackLng: 'en-US',

    // common namespace for the app
    ns: ['translations'],
    defaultNS: 'translations',

    /* debug: true, */

    interpolation: {
      // react already does escaping
      escapeValue: false,
    },

    react: {
      wait: true
    }
  });

i18n.default.addResourceBundle('es-PE', 'translations', esPe);

export default i18n;

@NullVoxPopuli what does not work? not showing translations in es-PE if you changeLanguage to it somewhere?

And why you add es-PE by addResourceBundle and not on init?

const localTranslations = {
  'en-US': { translations: enUs },
  'es-PE': { translations: esPE },
};

does setting:

react: {
      wait: true,
      omitBoundRerender: false
    }

solve the issue - if not it is not related to that change

my problem is specifically that when I have one component that has

export default compose(
  // ..
  translate('namespace'),
  // ...
)( ComponentName );

and another component that changes the currently selected locale, the component does not update.
This doesn't seem like it's true 100% of the time, as I have some composed components that do update on a locale switch, but the ones that don't just simply don't re-render / props don't change.

I've tried omitBoundRender with no success.

how do you change language?

and you mean your components not having the hoc do not rerender -> do you pass at least t function down to them...else sure...how should they rerender - if unchanged?!?

could you please provide a sample reduced to needed stuff to reproduce?

This is how I change language: https://github.com/sillsdev/appbuilder-portal/blob/master/source/SIL.AppBuilder.Portal.Frontend/src/ui/components/inputs/locale-select/index.tsx#L10

import * as React from "react";
import i18n from '@ui/../translations';

export interface IProps {
  value: string;
  onChange: () => void;
  className?: string;
}

export default class LocaleSelect extends React.Component {
  constructor(props = {}) {
    super(props);

    this.state = { value: props.value };
  }

  onSelect = (e) => {
    const selection = e.target.value;

    i18n.changeLanguage(selection);
    this.props.onChange(selection);
  }

  render() {
    const { value, onChange } = this.props;
    const { default: { options, language } } = i18n;
    const languages = Object.keys(options.resources);
    const selected = value || language;

    return (
      <select
        data-test-locale-switcher
        value={selected} onChange={this.onSelect}>
        { languages.map((locale,index) => (
          <option key={index} value={locale}>{locale}</option>
        )) }
      </select>
    );
  }
}

I'm always using the translate HOC.

Not sure if I'll have time for a small reproduction today. very busy! :)

hm...looks ok to me...not sure why it's not working for you...will need a sample for reproduction...sorry

same for me
not sure but it solved when I replaced I18nextProvider with reactI18nextModule

idk...no idea what it could be....the provider does work by passing i18n down via context while the module just pass i18n through internals.

i have the same problem. Not always all components are translated.

@emilgpa thanks - do you have some isolated sample to reproduce this?

No, I'm sorry.... :(

could you retry with [email protected] ??!?? a lot changed under the hood - hopefully this is "magically" solved (hope dies last)

I think that it can be because I change the language just after that i18next gets the language from localStorage.

I am very agree with you in you first post: "Hm...do this component not rerender have the wait option set to false? And you set language rather immediately after init -> not a user interaction -> this might be the only edge case i could think of resulting in some weird race condition"

There is any way to disable that i18next gets the language from localStorage? I tried useLocalStorage: false but it not works...

When I change the language by the user's interaction, it works well but I need to try it more. I remember that not always translate all the texts. For the moment, such an error no longer happens.

@emilgpa you're using the i18next-browser-languageDetector? if so that is not the case i described...what i meant is doing something like:

i18next.init()
i18next.changeLanguage()

So this still happens in v8.0.6?!?

Ok, I solved my first problem. The second have not happen yet and I would say that it never more will happen.

closing this for now as it seems to be solved with latest version @jokoso @NullVoxPopuli @wiscat feel free to reopen if still an issue at your project after upgrading

Looks like have same issues when use I18nextProvider, with reactI18nextModule works fine

@arturhtml as this was solved - please open a new issue with detailed steps on how to reproduce this. While i would love to help you i need more information why your specific code does not work...the Provider does not really much - so can't be it https://github.com/i18next/react-i18next/blob/master/src/I18nextProvider.js#L19 even if you state it works with reactI18nextModule i guess the root cause of this is somewhere else.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

leandrocamacho picture leandrocamacho  路  4Comments

pwiszowaty0 picture pwiszowaty0  路  4Comments

dawsbot picture dawsbot  路  4Comments

aniket-dalvi picture aniket-dalvi  路  4Comments

a-barbieri picture a-barbieri  路  4Comments