【问题标题】:React - setting up dynamic FormattedMessage - error "Messages must be statically"React - 设置动态 FormattedMessage - 错误“消息必须是静态的”
【发布时间】:2020-01-07 08:18:40
【问题描述】:

我正在开发一个反应应用程序 - 当用户输入一个文本字段时 - 我希望在同一行上有一个按钮 - 从“生成”更改为“保存”

<FormattedMessage
    id='generate'
    defaultMessage='Generate'
/>

但我想要这样的东西

<FormattedMessage
    id='generate'
    defaultMessage={valueName ? 'Save' : 'Generate'}
/>

什么的

<FormattedMessage
    id='generate'
    defaultMessage={valueName.length > 0 ? 'Save' : 'Generate'}
/>

但是当我实现这样的事情时,我得到了以下错误

“[React Intl] 消息必须能够静态评估才能提取。”

https://github.com/formatjs/react-intl/blob/master/docs/Components.md#formattedmessage

【问题讨论】:

    标签: reactjs react-intl


    【解决方案1】:

    您不能这样做,因为必须静态定义消息。您需要定义这两条消息,然后根据您的情况选择一条:

    const generateMsg = (
      <FormattedMessage id="generate" defaultMessage={"Generate"} />
    );
    
    const saveMsg = <FormattedMessage id="save" defaultMessage={"Save"} />;
    
    const msg = valueName ? saveMsg : generateMsg;
    

    我个人更喜欢使用一个小工具来抽象这种繁琐的语法:

    // Message.js
    
    import React from "react";
    import { injectIntl } from "react-intl";
    
    const Msg = injectIntl(({ id, intl }) => intl.formatMessage({ id }));
    
    const msg = ({ id }) => <Msg id={id} />;
    
    export default msg;
    

    用法:

    import { defineMessages } from "react-intl";
    import msg from './Message';
    
    const messages = defineMessages({
      save: {
        id: "save",
        defaultMessage: "Save"
      },
      generate: {
        id: "generate",
        defaultMessage: "Generate"
      }
    })
    
    //...
    <p>{msg(valueName ? messages.save : messages.generate)}</p>
    
    

    Source.

    请注意,msg 只能在 React 组件内部使用,因为它返回一个组件本身。这意味着它不能用于需要字符串的地方,例如原生 input'splaceholder, but the same applies to`。

    【讨论】:

    • 我可能需要将其实现为条件 html 片段 -- {valueName ? : }
    • 我会接受这个答案——尽管它有点复杂——因为它被一个按钮包围着,具有不同的动作