About Mixins & Higher Order Components
Sometimes it makes sense to extends a behavior of a component, while mixins are still alive, they’r not recommended anylonger, use Higher Order Components instead.
So instead of doing this:
function StoreMixin(...stores) {
var Mixin = {
getInitialState() {
return this.getStateFromStores(this.props);
},
...
}
}
var UserProfilePage = React.createClass({
mixins: [StoreMixin(UserStore)],
propTypes: {
userId: PropTypes.number.isRequired
},
...
})
You can do that:
function connectToStores(Component, stores, getStateFromStores) {
const StoreConnection = React.createClass({
getInitialState() {
return getStateFromStores(this.props);
},
...
render() {
return <Component {...this.props} {...this.state} />;
}
})
}
We just wrap the component and passes some additional props to it, it is a clean and generic solution for extending components without merging behaviors being implemented by React’s mixin merge logic.
You can read more about Higher Order Components here
Extending via ES6 Decorators
Sometimes it makes sense to extends a component without the need to wrap it manually, this technique is common in different frameworks to define components less verbosely when extra functionality is demanded.
Here is a short example how it works,
Lets extends the context of our component hierarchy with a print
function, so we use it in our render
method:
class MyPage extends Component {
static contextTypes = contextTypes;
render() {
return(
<div>{this.context.print('Hello World')}</div>
)
}
}
Assuming MyPage
is a child component of App
, here is how our App
component looks like:
var contextTypes = {
print: PropTypes.func.isRequired
}
var myContext = {
print: (m) => (m)
}
@context(contextTypes, myContext)
export default class App extends Component {
render() {
return (
<MyPage/>
)
}
}
And here is the code of the decorator:
export default function context(contextTypes, context) {
return function (DecoratedComponent) {
return class {
static childContextTypes = contextTypes;
getChildContext() {
return context;
}
render() {
return (
<DecoratedComponent {...this.props} />
);
}
}
}
}
The Decorator expects an expression and invokes the function with the given parameters and must return a function that expects the annotated component as a parameter, then we just return a class
with some context the wraps our component.
You can read more about Decorators here.