可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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