8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Reactコンポーネントのoptional propsにデフォルト値を設定する

Last updated at Posted at 2019-09-10

Reactコンポーネントを作っている際、storybookからpropsなしで呼び出してもエラーにならない方法が欲しかったので調べました。

Optional Props

typeに?をつければoptional propsを作れます。

import React from 'react';

export type HogeProps = {
  name?: string;
  age?: number;
};

const Hoge: React.FC<HogeProps> = (props: HogeProps) => {
  return (
    <>
      <div>{props.name}</div>
      <div>{props.age}</div>
    </>
  );
};

export default Hoge;

が、コンポーネント内で値をいじろうとするとundefinedの可能性があるためエラーとなります。
undefinedチェックを行えば回避可能ですがめんどくさいです。

import React from 'react';

export type HogeProps = {
  name?: string;
  age?: number;
};

const Hoge: React.FC<HogeProps> = (props: HogeProps) => {
  const fuga = props.name.substring(0, 2); // Object is possibly 'undefined'.
  const piyo = 100 + props.age; // Object is possibly 'undefined'.
  const fugaValue = props.name === undefined ? 'undefined' : props.name // OK

  return (
    <>
      <div>{fuga}</div>
      <div>{piyo}</div>
    </>
  );
};

export default Hoge;

デフォルト値を設定する

defaultPropsでデフォルト値を設定できますが、関数内では(string or number) | undefinedなのでエラーは解決できません。

import React from 'react';

... // Object is possibly 'undefined'.

Hoge.defaultProps = {
  name: "hage",
  age: 35
}

export default Hoge;

解決法

これを解決するには、コンポーネントの呼び出しではundefinedを許容しつつ内部ではundefinedが除外された別のtypeとして処理するようにします。

import React from 'react';

type PropsBase = {
  name?: string;
  age?: number;
};
const defaultValue = {
  name: "hage",
  age: 35
};
const PropsDefault: Required<
  Pick<PropsBase, { [Key in keyof PropsBase]-?: Key }[keyof PropsBase]>
> = defaultValue;
type Props = PropsBase & typeof PropsDefault;

export { defaultValue as hogeDefaultValue };
export type HogeProps = Props;

const Hoge: React.FC<PropsBase> = (_props: PropsBase) => {
  const props = (defaultValue && _props) as Props;
  const fuga = props.name.substring(0, 2); // OK
  const piyo = 100 + props.age; // OK

  return (
    <>
      <div>{fuga}</div>
      <div>{piyo}</div>
    </>
  );
};
Hoge.defaultValue = defaultValue;

export default Hoge;

----------

import React from 'react';
import Hoge from './Hoge'

const FooBar: React.FC = () => {
  return(
    <>
      <Hoge> // OK
      <Hoge name={"fusa"}> // OK
      <Hoge name={"fusa"} age={50}> // OK
    </>
  )
};

export default FooBar;

テストの際などにどうなるのか調べてないのでコメントで教えていただければ嬉しいです。

参考

Why don't use optional? in props params when interface work with defaultProps ?
https://tinyurl.com/y4c33as9 (Credit: BY/bocong#4119 at Reactiflux Discord server)

8
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?