2
\$\begingroup\$

I am learning redux by doing a small project. Everything is working fine, but I need to know how I can refactor such code. For this situation, it might be good to use if conditions like I have done, but what if I need to handle 7-8 languages? It won't be viable to use else if for 7 times. What is the proper way to handle such situation?

import { FRENCH } from '../../public/messages/fr';
import { ENGLISH } from '../../public/messages/en';

const initialState = {
  lang: FRENCH.lang,
  messages: FRENCH.messages
};
export const localeReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'LOCALE_SELECTED':
    if (action.locale === 'fr') {
      return { ...initialState, lang: FRENCH.lang, messages: FRENCH.messages };
    } else if (action.locale === 'en') {
      return { ...initialState, lang: ENGLISH.lang, messages: ENGLISH.messages };
    } break;
    default:
      return state;
  }
};
\$\endgroup\$
2
\$\begingroup\$

I don't know redux at all, so I might have missed something important so that my suggestion may be naive and doesn't work.
If so, my apologies, and don't shoot me too hard :)

That said, here is how I'd work:

  • first add a registry for the currently added langs
  • then merely use the right one depending on action.locale if it exists in registry, or keep initialState if not

Actually it results in something like this:

import { FRENCH } from '../../public/messages/fr';
import { ENGLISH } from '../../public/messages/en';

const initialState = {
  lang: FRENCH.lang,
  messages: FRENCH.messages
};
const langs = {
  fr: FRENCH,
  en: ENGLISH
}

export const localeReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'LOCALE_SELECTED':
      if (langs[action.locale]) {
        return {
          ...initialState,
          lang: langs[action.locale].lang,
          messages: langs[action.locale].messages
        };
      }
    default:
      return state;
  }
};
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

If you don't want to add/remove languages in your reducer file, you have to find a way to limit yourself to one import for all languages. For example you could add a new index.js file under ../../public/messages that would look like this:

// public/messages/index.js

import { FRENCH } from "./fr";
import { ENGLISH } from "./en";

export const defaultLocale = FRENCH;

export default {
  fr: FRENCH,
  en: ENGLISH
};

Then you could update your reducer to something like this:

// reducer.js

import messages, { defaultLocale } from "../../public/messages";

const initialState = {
  lang: defaultLocale .lang,
  messages: defaultLocale .messages,
};

export const localeReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'LOCALE_SELECTED':
      const locale = messages[action.locale] || defaultLocale;
      return { ...initialState, lang: locale.lang, messages: locale.messages };
      break;

    default:
      return state;
  }
}

This way, you will not need to touch your reducer when adding/removing locales since it will not know about which locales are available in the first place. By exporting a new defaultLocale constant in public/messages/index.js you will be also able to seamlessly change the default locale of your app without letting other parts of your app know about this change.

Keep in mind that in your original code sample, in case no locale was found, you returned an undefined state which would probably break your app. Going in a fashion similar to the one I suggested you will always return the default locale, so you should be safe.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I'm surprised by "in your original code sample, in case no locale was found, you returned an undefined state". Isn't state = initialState ensuring to have a defined state? \$\endgroup\$ – cFreed Nov 25 '16 at 1:11
  • \$\begingroup\$ i think it should be defaultLocale not defaultLang inside initialstate \$\endgroup\$ – Serenity Nov 25 '16 at 6:02
  • \$\begingroup\$ @Apprentice you're totally right. I'll updated my answer to fix this. \$\endgroup\$ – Ioannis Tziligkakis Nov 25 '16 at 8:16
  • \$\begingroup\$ @cFreed if you notice the first version of the code, you'll notice that in case of LOCALE_SELECTED if no matching locale is found, then nothing is returned if { ... } else if { ... }. The default state is returned in case no matching action.type is found. \$\endgroup\$ – Ioannis Tziligkakis Nov 25 '16 at 21:20
  • \$\begingroup\$ Oh yes, didn't realize. Looking at the code too quickly I had the impression that break; was part of the if() block. You're right. Thanks for the clarification. \$\endgroup\$ – cFreed Nov 25 '16 at 22:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.