val sprintf : format:Printf.StringFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
Multiple items module List
from Microsoft.FSharp.Collections
-------------------- type List<'T> = | ( [] ) | ( :: ) of Head: 'T * Tail: 'T list interface IEnumerable interface IEnumerable<'T> member GetSlice : startIndex:int option * endIndex:int option -> 'T list member Head : 'T member IsEmpty : bool member Item : index:int -> 'T with get member Length : int member Tail : 'T list static member Cons : head:'T * tail:'T list -> 'T list static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.map
Multiple items val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
-------------------- type int = int32
Full name: Microsoft.FSharp.Core.int
-------------------- type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
React performance in a Fable world
Plan
🧙🏻 How does react work ?
🔍 Measuring performance
💫 React in Fable
👩💻 Optimizations
Bonus
🤹 Micro optimizations
🚀 The future?
🥚🐣🐤💀
How does react work ?
« Virtual DOM » is a little short for an answer
🧙
DOM
An object model for HTML
A very imperative API
Not always slow but reflow (size recalculation) can be
React 101
Written in JS, made by Facebook, Open Source
A declarative syntax for the DOM
Elements
Native elements (HTML)
Custom Components
Basic types (string, number)
Arrays of all the above
Components
Props
State
~render
~shouldComponentUpdate
Reconciliation
Can be seen as an Element tree, distinct from the DOM
Triggered by our code
The new DOM is diffed with the previous one and change applied
Diff
Different types (different component or HTML element) are always re-created
HTML elements properties are compared with the previous ones and the changes are applied
Component instances are kept and asked if they should be recursed into via
shouldComponentUpdate. If true render is called.
Elements are always compared in order except if they have a Key prop
What do we want when we optimize
Limit the number of React Elements considered
Limit the amount of DOM ones returned
Ease the work of the diff algorithm with as much hints as we can
Limit the changes that really need to happen in the DOM
PureComponent
Provided by React in the React.PureComponent base class
Act like if shouldComponentUpdate was implemented with a shallow diff of state and props
So each field in props is compared by reference with the previous value
Functional components
Purely a different syntax to declare a Component
No shouldComponentUpdate implemented, they always re-render
Still useful versus just-a-function to give hints to React diff algorithm
Elmish
Elm-like library to manage web application state
Same pattern as Flux then Redux tried to apply in JS
We're mostly interested in the render part here
Measuring performance
Measure, Measure, Measure, Optimize?
🔍
User timing
React post performance events to browsers in development builds
Browsers show them when you take a measurement via their developer
tools.
Chrome
Also on Edge
Very useful, but doesn't work in Firefox and Edge is still inferior.
Use Chrome.
Chrome view is the best but need a little practice
It show both React events and JS callstack as a Flame Graph 👍
Finding anything at first is confusing. Zoom on top Timeline then adjust with scroll wheel.
Beware of React fiber: a single update can have continuations later
React profiler
Require recent (September 2018) React versions and DevTools
1:
yarn upgrade react react-dom
Works on Chrome and Firefox
Arrows move between renders
Grey = not rendered
Color = rendered, color coded for time
Early stage but extremely promising tool
No correlation with JS callstack
Start with it then move to a more complex analysis
Introducing the Canary
A very visual way to see render() calls
A PureComponent that show instance and global render() count
Show 🐣 when instance render() is 1, 🐤 when between 2 and 5 and ☠️ otherwise
Use only in deep places, potential complexity of structural equality depends on object graph size
Don't use because data is streamed from a server, the comparison should be in the state update, not each render.
Useful case is when used to pass multiple part of the parent model in Elmish as it involve a temporary Record or Tuple.
While more verbose a PureStatelessComponent with dedicated props can be better for performance (Worth it or not depends on your application, Measure !)
Often an occasion to better separate functional blocks in your app
Mostly worth it if the change can happen often
Not in the previous sample but nobodyTypingComponent is a perfect example of a component that can be Pure and can even return a pre-computed DOM tree (See micro optimizations).
OnClick expect a function, but this.Add expect a this parameter so a bind() is done each render, generated a new function and so React mutate the DOM to set the onClick
Can often be avoided by not rendering the parent component at all, mutating the DOM each render() if render() is never called is cheap.
As the DOM mutation has no risk of affecting visual rendering it's often cheaper for browsers than anything the risk a graphical reflow
Elements are values, store them when you can
They should often be in a PureComponent without any props too. React shouldn't be asked to diff things that never change.
React can concatenate (And use it's diff algorithm), JavaScript can concatenate, sprintf is slower than both.
1: 2: 3: 4: 5: 6: 7: 8:
// sprintf is very nice to usespan [] [str (sprintf"User %s is %i years old"nameage)]
// Javascript can do it cheaplyspan [] [str ("User "+name+" is "+ (unboxage) +" years old")
// Using react can limit how much of the DOM is changedspan [] [str"User "; strname; str" is "; ofIntage; " years old"]
Use arrays for collections of elements when possible
Prefer ofArray to ofList and arrays in general.
React use arrays so Fable will need to convert them anyway and JavaScript engines are heavily optimized for them.
Beware that F# doesn't stop you from mutating them but doing so would break PureComponent
Also beware that children of elements are a sequence but it should be a List as Fable optimize that case away.
Avoid extra function creation
An extension of the event handler case.
Fable can create a LOT of intermediate functions to simulate currying.
A frequent case is functional components that end up as <Unknwown> in DevTools due to that.
Decompile hot paths and look at JavaScript.
The future ?
« To Infinity and Beyond! »
🚀
PRs that need to be done
Stable dispatch in Elmish 😉
memo and friends
A better memo and ofFunc
There should be a way to use functional components that are functions with multiple parameters.