How to use FormattedMessage inside an option tag in React 0.14?

匿名 (未验证) 提交于 2019-12-03 08:41:19

问题:

I am trying to migrate my application from React 0.12 to React 0.14 and am having trouble with option elements that use react-intl FormattedMessage objects placed inside select tags.

Here is a sample JSX code:

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

This code works fine in React 0.12 and I see my translated option elements.

In react 0.14, I got this error:

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

I traced the message to this changeset in React that happened earlier this year:

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

How can I fix this issue? I can't be the only one trying to use internationalized option elements?

回答1:

This has always been an issue. React < 0.14 used to silently accept invalid DOM structure, in your case <span> elements inside <option> elements. The browser would then correct the DOM structure, and cause the virtual DOM managed by React to be out of sync with the real thing. You wouldn't see errors until you tried to re-render existing components instead of just re-mounting them.

react-intl V2.0.0, which will ship with support for React 0.14, allows you to use the Function-As-Child pattern to customize the way your Formatted* components render. See the "Function-As-Child Support" paragraph on this issue.

In your case, you would do:

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

I don't think there's a way to achieve this on the current stable version, 1.2.1.



回答2:

I had the same problem and solved it via the injectIntl().

This function is used to wrap a component and will inject the intl context object created by the IntlProvider as a prop on the wrapped component. Using the HOC factory function alleviates the need for context to be a part of the public API.

That means all you have to do is wrap your component with the injectIntl function, like that:

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) 

Hope that helps...



回答3:

As a little bit better alternative to @Alexandre Kirszenberg answer, it's also possible to inject intl object into component and use formatMessage function directly,

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,   // ... } 


回答4:

Use injectIntl to wrap the component you want to use the API inside ,so you can use the API, such as formattedMessage and so on. See react-intl/wiki/API



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!