Rewriting Transmission UI with React
February 3, 2017·6 minute readI remember it was about two months ago when I was talking with Eduardo Lanchares about the best stack for the next webapp. Sometimes you are at work and you are stuck with the current set-up of frameworks and tools that are quite difficult to change or refactor. This forces you to always work with the same mentality not allowing you to test new approaches to solve problems.
Following our desire to learn new stuff to make our life easier, we wanted to experiment with new technology to build a side project with a complete new stack that fits better with the app requirements.
Our experimental stack
Reviewing all of the features in the current Transmission web client, the stack we chose was React for the user interface, Mobx for the state management and CSS modules for all the stuff related with the application styles, with a new build process managed by Webpack.
On the other hand, and with the above stack in mind, we decided to use some best practices for the long term quality of this project. Some of these were things like a strict set of Eslint rules, unit tests, UI tests and internationalization.
With this decision we wanted to achieve a more reliable interface, better performance, security and correctness. In conclusion a better way to maintain this web application.
Components
Our new application stores each component in an independent folder for each of them, with all the related stuff within. Things like styles, tests or subcomponents live together. This lets us manage all the application components understanding all the dependencies between them and achieving the best decoupling possible.
State management
In a traditional web application implemented with jQuery you would keep updating all the UI manually, after realizing that some elements were outdated. Those changes would usually come from some user interaction or from server updates, so the concept of application state was almost inexistent.
With the new stack managed by React and Mobx, we follow the one way data flow convention, which makes it easier to reason about the application state. All this state is managed in Mobx containers called stores. This is a really good diagram to understand how it works:
Mobx uses the following main concepts to model your application state:
observable
properties: basic tracked propertiescomputed
properties: derived properties from observable onesactions
: methods to update the statereactions
: side effects to be executed for each state change
isPreferencesDialogShown
observable property. That change produces an update in observer components. In
this case PreferenceDialog
reacts to this change and re-renders itself,
resulting in dialog shown in the UI.Styling
For a really long time we have been styling HTML components through a list of CSS classes referenced by class attributes in your elements. New tools have appeared during the last 5 years to improve our life like SASS, LESS or CSS Modules.
If you are used to code big sets of components you can make the common mistake of reuse style classes for different components. But what happens when the styles from those components start to differ? You are in a trouble.
As we said before, in our stack we decided to use CSS Modules to style all our components. We think that this is the best approach to achieve a modular and reusable set of classes. All the required classes for each component live together. This is really good in terms of maintainability because it’s trivial to decouple components. CSS Modules lets you play with composition so you get the best characteristics from both worlds.
content
and logo
. These names are used to refer classes in the
stylesheet file.viewConnectionDialog/index.js
:fileConnectionDialog/styles/index.css
:Tests
The original application had no tests at all so it was easy for us to improve that aspect.
Integrating this new set of tests to some CI we can be more confident about future changes that we apply to the application.
As we can see in this example we are rendering the Progress bar component with mocked torrent data.
Then with the snapshot technique we can ensure that the rendered result is what we expect comparing with previous snapshot. Testing components in this way is a as simple as record JSX code.
Extra features
Reviewing all available features in the original Transmission web interface we discovered broken features like Desktop notifications. We wanted to restore them because we think it’s a really nice feature to have.
Furthermore, one extra feature that the new interface includes is drag and drop file support for torrent files. This boosts the common use case of quickly adding a torrent file as you can see in this example:
Conclusion
We started this project to play with new technology to be able to understand all the challenges a bigger project would face if you chose some specific stack. At some point we saw how easy was to implement new features that were included in the original interface. So we decided to push forward and set a personal goal: Implement all of them. Today we can say that we’ve achieved 95% of all features.
Our last goal is to present this project to the community to be evaluated. We decided to respect as much as possible the original interface for two main reasons:
- We didn't want to raise a debate in UI design. So we decided to follow the current design, we just wanted to propose a new code architecture.
- We didn't want to impact the end users in case that this code were considered for inclusion in the main Transmission repository.
Lastly, even if the project dies out, for whatever reason, we’re happy anyway, because we learnt a lot of things and had a really fun time during its development. :D