As others have mentioned, this is probably a terrible idea, but in spirt “anything is possible”, this happens here.
First we need to define an interface for testing the support. It is fully flexible, with convenience by default.
var hasOwn = Function.prototype.call.bind(Object.prototype.hasOwnProperty); function testProps(obj, thisArg){ return Object.keys(obj).every(function(propName){ var test = obj[propName], prop = thisArg.props[propName]; if (typeof test === "function"){ return test(prop); } else { return prop === test; } }); }
An example of what you pass to this is {foo: true, bar: odd} , where odd returns true if the number is odd. When called with <Component foo={true} bar={7} /> , mixin will be "active".
Using this, we can define a function that takes an array {mixin: mixin, condition: tests} , where the tests are in the above format.
function conditionalizeMixins(mixins){ var proxyMixin = {}; var runMixins = function(lifeCycleKey){ return function(){ var component = this, args = arguments; var result; mixins.forEach(function(mixin){ if (testProps(mixin.condition, component)) { result = mixin.mixin[lifeCycleKey].apply(component, args); } }); return result; } } mixins.forEach(function(mixin){ Object.keys(mixin.mixin).forEach(function(key){ if (proxyMixin[key]) return; proxyMixin[key] = runMixins(key); }); }); return proxyMixin; }
Now we can define our mixins like this:
mixins: [conditionalizeMixins([ { mixin: myMixin, condition: {foo: true, bar: false} }, { mixin: myMixin, condition: {foo: false, num: function(x){return x%2===1}} } ])]
See if there is a way to split this into two components, not one component. This is probably the best way to do this.
Notes on the above code:
- performance is small, but can be optimized.
- If several conditional mixins define, for example, getInitialState, only the last active
- it hides errors, for example. if you define doFoo that returns a string and none of the mixins are active, it will silently return undefined
jsbin