Mixins

Components are great to achieve reusability, but what if different components in different domains share the same behavior?

We do not want duplicated code in our applications and React give us a tool that we can use when we want to share functionalities across various components—mixins.

Using mixins is deprecated, but it is worth understanding the problems they try to solve and see what the possible alternative solutions are. Also, it could happen that you might have to work on a legacy project that uses an older version of React, and it makes sense to know what mixins are and how to deal with them.

First of all, mixins work only with the createClass factory, so if you are using classes, you cannot use mixins, and that is one of the reasons why their use is discouraged.

Suppose you are using createClass in your application and you find yourself needing to write the same code into different components. For example, you need to listen to the window resize event to get the size of the window and do some operations accordingly.

One way of using a mixin is to write it once and share it across the different components. Let's delve into the code.

A mixin can be defined as an object literal that has the same functions and attributes of a component:

  const WindowResize = {...};

To communicate with the component, mixins usually use the state. With getInitialState, the state gets initialized with the initial innerWidth of a window:

  getInitialState() { 
return {
innerWidth: window.innerWidth
};
}

Now, we want to keep track of the changes, so when the component mounts, we start listening to the window resize event:

  componentDidMount() { 
window.addEventListener('resize', this.handleResize);
}

We also want to remove the event listener as soon as the component unmounts, which is critical, thus freeing the memory and not leaving unused listeners attached to the window:

  componentWillUnmount() { 
window.removeEventListener('resize', this.handleResize);
}

Finally, we define the callback to be called every time the window resize event is fired.

The callback function is implemented to update the state with the new innerWidth component so that the component that is using the mixin re-renders itself with the fresh value that's available:

  handleResize() { 
this.setState({
innerWidth: window.innerWidth
});
}

As you can see from the preceding snippet, creating a mixin is very similar to creating a component.

Now, if we want to use the mixin in our component, we just have to assign it to the array of mixins, which is a property of the object:

  const MyComponent = React.createClass({ 
mixins: [WindowResize],
render() {
console.log('window.innerWidth', this.state.innerWidth);
...
}
});

From this point on, the value of innerWidth of the window will be available in the state of our component, and the component will re-render with the updated value any time  innerWidth changes.

We can use the mixin in many components at a time and also use multiple mixins for each component. A nice feature of mixins is that they can merge life cycle methods and the initial state.

For example, if we use our WindowResize mixin in a component where we also define a componentDidMount hook, both will be executed in order.

The same happens in the case of multiple mixins that use the same life cycle hooks.

Now, let's go through the problems of mixins. In the next section, we will see what the best technique is to achieve the same result without all the issues it usually brings.

First of all, mixins sometimes use internal functions to communicate with the component.

For example, our WindowResize mixin could expect the component to implement a handleResize function and give developers the freedom of doing some operations when the size changes, instead of using the state to trigger the update.

Alternatively, instead of setting the new value into the state, the mixin could require the component to call a function—something like getInnerWidthin our example—to get the actual value.

Unfortunately, there is no way for us to know of the list of methods that have to be implemented.

This is particularly bad for maintainability because, if a component uses multiple mixins, it ends up implementing different methods, which makes it difficult to eliminate the code when some mixins are removed, or they change their behavior.

A very common problem with mixins is clashing. Though it is true that React is smart enough to merge life cycle callbacks, it cannot do anything if two mixins define or require the same function name or use the same attribute in the state.

This is pretty bad in big codebases because it can give us unexpected behaviors and it makes it very hard to debug issues.

As we saw in the WindowResize example, mixins tend to communicate with the component using the state. So, for example, a mixin can update a special attribute in the state of a component, and then the component re-renders, taking into account the new attribute.

This makes components use the state even if it is not needed, which is bad because we have seen that we should avoid using it as much as we can to improve reusability and maintainability.

Last but not least, sometimes it can happen that some mixins depend on other mixins. For example, we could create ResponsiveMixin, which changes the visibility of some components according to the size of the window, which is provided in the WindowResize mixin.

This coupling between mixins makes it very hard to refactor the components and scale the application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.6.75