web-dev-qa-db-ja.com

React-intl、TypescriptでAPIを使用

React-intl APIのformatMessage関数を使用して、プレースホルダーとしてメッセージを挿入したいのですが、この関数にアクセスする正しい方法がわかりません。

これが私が持っているものの簡略版です:

//index.tsx
<IntlProvider locale={`fr-FR`} messages={messages_fr}>
    <NameForm/>
</IntlProvider>,

//nameForm.tsx
interface NameFormProps {
   intl?: InjectedIntlProps,
}

export default injectIntl(NameForm);

class NameForm extends React.Component<NameFormProps, {}> {

render() {
    let namePlaceholder = this.props.intl.formatMessage(
        {id: "NAME_PLACEHOLDER",
        defaultMessage: "name"
    });

    return (
        <form>
            <input placeholder={namePlaceholder} type="text"/>
        </form>
    );
}

IntlShapeはformatMessageメソッドを提供していないようであるため、intlpropのタイプとしてInjectedIntlPropsを使用しました。

?を追加しました「プロパティ 'intl'がありません」(ただし、injectIntl​​はこのプロパティなしでコンポーネントを返すことになっていないのですか?)

これでコンパイルされますが、実行時にエラーが発生します(「デフォルトのエクスポートには明示的な名前がないため、「未定義のプロパティ 'displayName'を読み取れません」と思います)。

正しい方向に進んでいないように感じますが、TypeScript/react-intlプロジェクトの例が見つかりません。

ご協力いただきありがとうございます !

9
Emarco

この問題は、TypeScript定義のバージョンが原因でした。 @ types/react-intl ":" ^ 2.2.0 "を使用すると、チャームのように機能します。

(編集)それを機能させるために必要ないくつかの変更:

//index.tsx
<IntlProvider locale={`fr-FR`} messages={messages_fr}>
  <NameForm/>
</IntlProvider>,

//nameForm.tsx
interface NameFormProps extends InjectedIntlProps {
  placeholder: string,
}

class NameForm extends React.Component<NameFormProps, {}> {

  render() {
    let namePlaceholder = this.props.intl.formatMessage({
       id: this.props.placeholder,
       defaultMessage: "name"
      });

    return (
      <form>
        <input placeholder={namePlaceholder} type="text"/>
      </form>
    );
}

export default injectIntl(NameForm);
7
Emarco

同じ問題を処理しているときに、質問で述べたようにメンバーとしてInjectedIntlPropsを含めたり、別の回答で述べたようにそこから拡張したりしても、タイプチェッカーが満たされないことがわかりました。 InjectedIntlPropsから拡張する場合、injectIntlの呼び出しがチェックされましたが、JSXで結果のコンポーネントを使用すると、intlプロパティを提供することが期待されました。ただし、次の戦略でこれを解決しました。

    interface NameFormProps {
        // Include all custom properties here.
    }

    class NameForm extends React.Component<NameFormProps & InjectedIntlProps, {}> {
        // Class body.
    }

    export default injectIntl(NameForm);
13
Braden Walters

既存のソリューションはどちらも私にはうまくいきませんでした。代わりに、injectIntlがプロパティにInjectedIntlPropsを含めるように推測したことが原因でした。

これを修正するには、ラップされたコンポーネントに必要な小道具をinjectIntlに明示的に指示する必要がありました。

interface NameFormProps {
}

class NameForm extends React.Component<NameFormProps & InjectedIntlProps> {
}

export default injectIntl<NameFormProps>(NameForm);

小道具がない場合は、少し変更する必要があります。

class NameForm extends React.Component<InjectedIntlProps> {
}

export default injectIntl<{}>(NameForm);
4
Ryall

更新しました:

.xへのアップグレード に関するドキュメントを読んだ後、useIntlフックを使用するだけの簡単な方法があることがわかりました。

サンプルコード:

import { FormattedMessage, useIntl } from 'react-intl'


type Props = {
  placeholder: string,
}

function MyComponent({ placeholder }: Props) {
  const intl = useIntl()

  return (
    <input placeholder={intl.formateMessage({id: placeholder})} type="text"/>
  )
}

export default MyComponent

古い:

React-intlの新しいバージョン(3.12.0)では、@types/react-intlはもう必要ありません。react-intlには独自の型定義があり、InjectedIntlPropsはもう存在せず、名前が付けられています。代わりにWrappedComponentProps

私のサンプルコード:

import { FormattedMessage, injectIntl, WrappedComponentProps } from 'react-intl'

type Props = {
  placeholder: string,
} & WrappedComponentProps

function MyComponent({ placeholder, intl }: Props) {

  return (
    <input placeholder={intl.formateMessage({id: placeholder})} type="text"/>
  )
}

export default injectIntl(MyComponent)
0
Spark.Bao