Search code examples
javascriptreactjsreact-nativereact-proptypes

React PropTypes - OneOf list of objects


I have the following array:

export const VALID_LANGUAGES = [
  { label: "English", value: "en" },
  { label: "French", value: "fr" },
  { label: "Italian", value: "it" },
  { label: "Portuguese", value: "pt" },
  { label: "Spanish", value: "sp" },
];

And I want to make sure that a component receive, as a prop "language", one of these values. How can I do it?

MyComponent.propTypes = {
  language: PropTypes.oneOf(VALID_LANGUAGES).isRequired, // Doesn't work :( 
};

Solution

  • I think you just need to map the array to a list of valid language entries. The label property seems like the value you want.

    language: PropTypes.oneOf(VALID_LANGUAGES.map(({ label }) => label).isRequired
    

    If you instead want the language code just map the value.

    language: PropTypes.oneOf(VALID_LANGUAGES.map(({ value }) => value).isRequired
    

    UPDATE

    Actually, I just tested your original code and it also works. Each value is validated until the last option "Klingon" which is invalid and a proptypes error is logged. Here's a codesandbox demo:

    Edit react-proptypes-oneof-list-of-objects

    const VALID_LANGUAGES = [
      { label: "English", value: "en" },
      { label: "French", value: "fr" },
      { label: "Italian", value: "it" },
      { label: "Portuguese", value: "pt" },
      { label: "Spanish", value: "sp" }
    ];
    
    const MyComponent = ({ language }) => <div>Language: {language.label}</div>;
    MyComponent.propTypes = {
      language: PropTypes.oneOf(VALID_LANGUAGES).isRequired
    };
    
    export default function App() {
      const [language, setLanguage] = React.useState(0);
      return (
        <div className="App">
    
          <select onChange={(e) => setLanguage(e.target.value)} value={language}>
            <option value={-1} disabled>
              Select a Language
            </option>
            {VALID_LANGUAGES.map((language, index) => (
              <option key={language.value} value={index}>
                {language.label}
              </option>
            ))}
            <option value={-1}>Klingon</option>
          </select>
    
          <MyComponent language={VALID_LANGUAGES[language]} />
        </div>
      );
    }
    

    Perhaps you can clarify what and/or how your code isn't working.