我有两个HOC,为组件添加上下文,如下所示:
const withContextOne = Component => class extends React.Component {
render() {
return (
<ContextOne.Consumer>
{context => <Component {...this.props} one={context} /> }
</ContextOne.Consumer>
);
}
};
export default withContextOne;
我只想要一个语法简洁的方法来用这个HOC包装一个组件,这样它就不会对我的JSX结构造成太大的影响。
export default withContextOne(withContextTwo(MyComponent))
这种方式是最简洁的,但不幸的是它打破了我的单元测试。{ withContextOne(withContextTwo(<Component />)) }
这引起了我的错误说法函数作为React子函数无效。如果从渲染中返回Component而不是<Component />,则可能会发生这种情况。
const HOC = withContextOne(Component)
然后简单地用<HOC {...props}/>
等渲染。我不喜欢这个方法,因为它改变了我的JSX中组件的名称
您可以使用装饰器来缓解链式HOC的语法痛苦。我忘了你需要哪个特定的babel插件,它可能(仍然)是babel-plugin-transform-decorators-legacy
或可能是babel-plugin-transform-decorators
,取决于你的babel版本。
例如:
import React, { Component } from 'react';
import { withRouter } from 'react-router';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { resizeOnScroll } from './Resize';
@withRouter
@resizeOnScroll
@injectIntl
@connect(s => s, (dispatch) => ({ dispatch }))
export default class FooBar extends Component {
handleOnClick = () => {
this.props.dispatch({ type: 'LOGIN' }).then(() => {
this.props.history.push('/login');
});
}
render() {
return <button onClick={}>
{this.props.formatMessage({ id: 'some-translation' })}
</button>
}
}
然而,装饰者的警告是测试成为一种痛苦。你不能使用const
的装饰器,所以如果你想导出一个“干净”的未修饰的课你运气不好。这就是我现在通常做的,纯粹是为了测试:
import React, { Component } from 'react';
import { withRouter } from 'react-router';
import { injectIntl } from 'react-intl';
import { connect } from 'react-redux';
import { resizeOnScroll } from './Resize';
export class FooBarUndecorated extends Component {
handleOnClick = () => {
this.props.dispatch({ type: 'LOGIN' }).then(() => {
this.props.history.push('/login');
});
}
render() {
return <button onClick={}>
{this.props.formatMessage({ id: 'some-translation' })}
</button>
}
}
export default withRouter(
resizeOnScroll(
injectIntl(
connect(s => s, ({ dispatch }) => ({ dispatch }))(
FooBarUndecorated
)
)
)
);
// somewhere in my app
import FooBar from './FooBar';
// in a test so I don't have to use .dive().dive().dive().dive()
import { FooBarUndecorated } from 'src/components/FooBar';
您可以在返回包装组件之前设置displayName
。
const withContextOne = Component => {
class WithContextOneHOC extends React.Component {
render() {
return (
<ContextOne.Consumer>
{context => <Component {...this.props} one={context} /> }
</ContextOne.Consumer>
);
}
}
WithContextOneHOC.displayName = `WithContextOneHOC(${Component.displayName})`;
return WithContextOneHOC;
};
这将把<WithContextOneHOC(YourComponentHere)>
放在你的React树中,而不仅仅是通用的React <Component>
元素。