ZF4 Blog

Visualizing React

How did your holiday go?

Over the Christmas holiday I like to do a few things in addition to making merry, enjoying time with family, friends and dogs and catching up on the best of the year's TV. Updating my nest of *nix pooters to the latest LTS version, getting some early seeds into the greenhouse, and spending some time getting into some new code generally does the job.

This year, the 'coding challenge' fell to getting seriously into React & D3. I've been playing with an idea to create a game based around a radar screen, using sensors in the garden to feed an early warning system for 'The Grey Squirrel', purloiner of all things edible in my garden, and nemesis of my two dogs. The idea is to put some motion sensors around the garden and feed them into the radar to locate the enemy, and send the dogs on 'hunt n kill' missions using the labyrynth of tunnels that constitutes the country pile. I'm even thinking about Star Wars like auto firing air rifles (all you animal apologists - not really - it's illegal in the UK, but nice to think about.)

Those that know me well enough, also know that I don't much like Javascript, (subject for another blog!) but there is only one way to do this, so I gritted my teeth and got on with it.

Now, there is a wealth of t'internet info on React, on D3 and a bit on using the two together. I spent 3 days wading through it, gnashing teeth at the inanities of Javascript, which version of it to use, ES4, 5, 6, 7 ...., why da feck do I need to compile, it's an interpreted language, why do I need 57 development requires and only 5 production requires? Wondering why the examples I was following don't work on my machine, (only to figure out that BC breaks in the JS world are hardly worth a mention!)

Eventually, I got started and got into some real code. Switched the screen on, had the radar sweep working. Bonza. Just spent two days in some totally alien environment and came out the other side. And got Redux working too - bonus!

Then I decide it would be real cool to add some controls to my radar screen. That's where I got lost :-(

I need to see it in pictures

By this time, I'd got a bunch of containers and components. But trying to visualize the communication flow between them in a bunch of alien code was stretching the little grey cells too far. I need to see this in a picture!

Off to t'internet again, only to find that JS world don't do structured diagrams. Bugger! Hang on a minute, I know UML. Search again. Nope. Some stuff about using it, but nothing concrete. So, borrowing a paradigm from the XML world, I decided to come up with a 'React Definition Syntax' for UML, that I hope will help others as a way of communicating React Universes to others. This is just a start. Help by commenting below.

The toolset

I've longed used PlantUml as a quick n dirty way of producing UML diags. I like that it is just text, writes like a program, but quickly visualizes class and components and any other UML diagram type you care to mention. I've often used it in design sessions with other other engineers to quickly map out an application. Best, as it is just text, you can simply include it in the code base or Agile work systems. A large number of Agile work systems and engineer IDEs support it as a plugin, so shipping visual ideas around is a breeze.

Drawing UML using point n click graphics programs is probably a major reason why UML doesn't enjoy the popularity it deserves.

But the best bit is that PlantUml doesn't just support standard UML, it effectively allows you to create your own dialect.

The React-UML dialect

Caveat

In the following, I am pre-supposing that you are using React + some sort of central store mechanism, Redux seems to be good, and that you are splitting your app into Containers, handling store and state change, and Components, handling representation and maybe some state. If not, still read on and adapt this to your own needs.

Draw using a class diagram

Class diagrams in UML are perhaps the most easily understood and familiar to engineers, so it makes sense to use them. This of course doesn't stop you using others UML diagram types, but we gotta start somewhere.

React with Redux can be broadly broken down into:

  • (store) Providers
  • Containers
  • Components
  • State changes
  • Prop(erty) changes
  • State changes
  • Backflow events (subordinates triggering events on parent classes)

Providers, Containers and Components can all be defined as Classes.

Plantuml Image React JSX
Provider
class Redux << (P,yellow) Provider>> {
    ~store
}
<Provider store={store}\>
</Provider\>
Container
class RadarContainer << (C,red) container>> {
    ~store
    ==state==
    ==props==
}
<RadarContainer/>
or more typically
<Provider store={store}>
    <RadarContainer/>
</Provider>
Component
class Display << (C,blue) component >> {
    ==state==
    ==props==
    # svgHeight: number
    # svgWidth: number
    # diameter: number
    # radius: number
    # hubRadius: number
}
<Display {...props}/>

If you aren't using a state or props section in the class, simply remove it. It's up to you as to whether you want to add all the boilerplate methods to each class. For me, its more important to concentrate on the lifecycle events, where we hoist up state and so on, where the interaction is. This can be done with judicious use of connectors.

Plantuml Image Notes
Two way store interaction
Redux <..> RadarContainer
Dashed two headed arrow indicates that the linked components share their stores. A change initiated in any component is reflected wherever that store is surfaced.
Aggregation and Composition
RadarContainer *-- SweepContainer
RadarContainer *-- ControlContainer
RadarContainer o-- Display
Whether you want to show the symantics of UML aggregation and composition is dependent on your need. You may simply join two components with a line RadarContainer -- SweepContainer but it is often useful to denote the `parent` with some sort of arrow head
Event Backflow
class RadarControls << (C,blue) component >> {
    ==state==
    ==props==
    # controls:array
    # controlHandler()
    ==methods==
    +handleToggleEvents()
}
class Toggle << (C,blue) component >> {
    ==state==
    # value
    ==props==
    # id: number
    # label: string
    # onClick()
}
RadarControls o-- Toggle
RadarControls "handleToggleEvents" <.. "onClick" Toggle
Here we show the parent method that is being used as a callback by the child and the props function that ties the two together. We label each end of the flowback arrow with the names of the function/method that they relate to. In the parent, we add the method into a methods section. In the child we denote the props function by suffixing with the () braces (all standard PlantUml syntax.) Note that the Toggle component also has some state of its own, indicating something in the component is going to change that state and cause a redraw.
Component Instances
class "StartStop:Toggle" << (C,lightblue) instance >>
Toggle <|-- "StartStop:Toggle"
It is sometimes useful to show concrete instances of a particular component class. We can do this using a standard UML inheritance arrow with an 'instance' sterotype. The instance name should follow the convention <instanceName>:<className>

The diagram in toto

Radar as React visualized

The PlantUml script:

@startuml
title Radar

class Redux << (P,yellow) Provider>> {
    ~store
}

class RadarContainer << (C,red) container>> {
    ~store
}

class ControlContainer << (C,red) container>> {
    ~store
    ==methods==
    +handleEvents()
}

class SweepContainer << (C,red) container>> {
    ~store
    ==props==
    # radius:number
    # hubRadius: number
}

class Bezel << (C,blue) component >> {
    ==props==
    # radius: number
}

class Display << (C,blue) component >> {
    ==props==
    # svgHeight: number
    # svgWidth: number
    # diameter: number
    # radius: number
    # hubRadius: number
}

class Hub << (C,blue) component >> {
    ==props==
    # radius:number
}

class Sweep << (C,blue) component >> {
    ==props==
    #dim:object
}

class RadarControls << (C,blue) component >> {
    ==props==
    # controls:array
    # controlHandler()
    ==methods==
    +handleToggleEvents()
}

class Toggle << (C,blue) component >> {
    ==state==
    # value
    ==props==
    # id: number
    # label: string
    # onClick()
}

class "StartStop:Toggle" << (C,lightblue) instance >>

Redux <..> RadarContainer
Redux <..> ControlContainer
Redux <..> SweepContainer
RadarContainer *-- SweepContainer
RadarContainer *-- ControlContainer

RadarContainer o-- Display

Display o-- Bezel
Display o-- Hub

SweepContainer o-- Sweep

ControlContainer o-- RadarControls
ControlContainer "handleEvents" <.. "controlHandler" RadarControls
RadarControls o-- Toggle
RadarControls "handleToggleEvents" <.. "onClick" Toggle

Toggle <|-- "StartStop:Toggle"
@enduml

Now we can start to reason about our component structure, start to spot where refactoring makes sense, and better still, share this with our colleagues to get their input as well. Can you see where some refactoring may be in order above?

Summary

A picture paints a thousand words. Making PlantUml a part of your toolkit means you can quickly sketch out all sorts of UML type diags that most engineers understand, with a few lines of text. In an Agile world, no-one is expecting the diagram to be maintained, your (well documented) code and tests should be the canonical truth. If you are anything like me though, sometimes that picture can just help you see the blindingly obvious that is otherwise hidden.

Resources

PlantUml

Check out your IDE's plugin repo for support. It is offered in most of the mainstream ones, (Jetbrains, Eclipse, Netbeans etc). Many development workflow system providers also support PlantUml. If you are an Atlassian Confluence user, that supports PlantUml for instance.

Smart and Dumb components - Dan Abramov

Lifting state in React