如何在 React 0.14 的选项标签中使用 FormattedMessage?

IT技术 reactjs
2021-04-29 15:21:17

我正在尝试将我的应用程序从 React 0.12 迁移到 React 0.14,并且在使用放置在 select 标签中的react-intl FormattedMessage 对象的选项元素时遇到了问题

这是一个示例 JSX 代码:

<select>
<option value="value1"><FormattedMessage message={this.getIntlMessage('key1')}/></option>
<option value="value2"><FormattedMessage message={this.getIntlMessage('key2')}/></option>
</select>

这段代码在 React 0.12 中运行良好,我看到了我翻译的选项元素。

在 react 0.14 中,我收到此错误:

Only strings and numbers are supported as <option> children.

我将消息追溯到今年早些时候在 React 中发生的这个变更集:

https://github.com/facebook/react/pull/3847/files

我该如何解决这个问题?我不能是唯一一个尝试使用国际化选项元素的人吗?

4个回答

这一直是一个问题。React < 0.14 用于静默接受无效的 DOM 结构,在你的情况下<span>元素内的<option>元素。然后浏览器会修正 DOM 结构,导致 React 管理的虚拟 DOM 与真实事物不同步。在您尝试重新渲染现有组件而不是重新安装它们之前,您不会看到错误。

react-intlV2.0.0 将支持 React 0.14,允许您使用 Function-As-Child 模式来自定义Formatted*组件的渲染方式。请参阅有关此问题的“儿童功能支持”段落

在你的情况下,你会这样做:

<FormattedMessage message={this.getIntlMessage('key1')}>
  {(message) => <option value="value1">{message}</option>}
</FormattedMessage>
<FormattedMessage message={this.getIntlMessage('key2')}>
  {(message) => <option value="value2">{message}</option>}
</FormattedMessage>

我认为在当前的稳定版本 1.2.1 上没有办法实现这一点。

我遇到了同样的问题并通过 injectIntl​​() 解决了它。

此函数用于包装组件,并将注入由 IntlProvider 创建的 intl 上下文对象作为包装组件上的props。使用 HOC 工厂函数减轻了将上下文作为公共 API 一部分的需要。

这意味着您所要做的就是使用 injectIntl​​ 函数包装您的组件,如下所示:

import React, {Component, PropTypes} from 'react';
import {defineMessages, injectIntl, intlShape} from 'react-intl';

const messages = defineMessages({
    firstoption: {
        id: 'mycomponent.firstoption',
        defaultMessage: 'Coffee',
    },
    secondoption: {
        id: 'mycomponent.secondoption',
        defaultMessage: 'Tea',
    }
});

class MyComponent extends Component {
    render() {
        const {formatMessage} = this.props.intl;

        return (
          <div>
             <select>
                <option value="value1">{formatMessage(messages.firstoption)}</option>
                <option value="value2">{formatMessage(messages.secondoption)}</option>
             </select>
          </div>
        );
    }
}

MyComponent = {
    intl   : intlShape.isRequired
};

export default injectIntl(MyComponent)

希望有帮助...

作为@Alexandre Kirszenberg 答案的更好替代方案,也可以将intl对象注入组件并formatMessage直接使用函数,

import { injectIntl, intlShape, defineMessages, FormattedMessage } from 'react-intl';

const AddressForm = ({ intl, street, number, postalCode, city, onChange }) => {
  return (
    <form id="paymentAddress">
      // ...
      <fieldset className="form-group">
        <label htmlFor="country"><FormattedMessage { ...messages.country } />:</label>
        <div>
          <select name="country">
            <option value="DE">{intl.formatMessage(messages.de)}</option>
            <option value="UK">{intl.formatMessage(messages.uk)}</option>
            <option value="CH">{intl.formatMessage(messages.ch)}</option>
          </select>
        </div>
      </fieldset>
    </form>
  );
};

AddressForm.propTypes = {
  intl: intlShape.isRequired,
  // ...
}

使用react-intlv4.0.0,您可以这样做:

    <select
      className="content"
      name="type-enquiry"
      defaultValue="Type of Enquiry"
      onChange={handleChange}
      required
     >
      <option name="options" disabled hidden>
                Choose
      </option>
        <FormattedMessage id='contact.enquiry.a' key={'op' + '-' + 'a'}>
           {(message) => <option value='a'>{message}</option>}
        </FormattedMessage>
        <FormattedMessage id='contact.enquiry.b' key={'op' + '-' + 'b'}>
           {(message) => <option value='b'>{message}</option>}
        </FormattedMessage>
        <FormattedMessage id='contact.enquiry.c' key={'op' + '-' + 'c'}>
           {(message) => <option value='c'>{message}</option>}
        </FormattedMessage>
    </select>

示例代码