@descarteslabs/cycle-widgets
v0.1.31
Published
Widgets written in Cycle.js and Remcycle
Downloads
44
Keywords
Readme
cycle-widgets
Widgets written in Cycle.js and Remcycle
Best Practices and Things to Look out For scratch-pad:
directory structure:
- index.js - exports the remcycle component and re-exports the redux action constants and creators
- view.jsx - exports the view React component and/or the reactSinksCombiner for the Cycle component
- redux.js - exports the action type constants and action creators for the component
- sources.js - [optional] exports the array of source HOC transformations (otherwise defined in index.js)
- sinks.js - [optional] exports the array of sink HOC transformations (otherwise defined in index.js)
React
- try to keep components as pure functions
- be careful with
shouldComponentUpdate
or with recompose'sshouldUpdate
orpure
as they prevent unnecessary renders, but if you're not careful, they'll also prevent necessary renders
recompose
- use
recompose
for adding view-specific functionality to React components (so that they don't have to be class components, if possible)
- use
styling, CSS
- use
styled.div
andstyled.span
fromstyled-components
in place ofdiv
s,span
s, etc when you know how those elements should be styled and/or how they should style their children elements - in general, assume your React components can be rendered anywhere in any container - thus, their CSS should be written such that the components will know how to render themselves given any abritrarily-sized container (depending on how responsive you want them to be)
- i.e. heights, widths, max-heights and max-widths should almost always be
inherit
or100%
or at the very least percentages - use flexbox for layout almost everywhere
- if layout has to change depending on container (i.e. parent) size, wrap your component with react-measure to get the container's height and width, then act accordingly
- i.e. heights, widths, max-heights and max-widths should almost always be
- use
most and streams
- use
tap(::console.log)
to inspect the stream - if a stream is not logging, then you're not combining/sampling the streams correctly or you're not using it anywhere (and thus, it isn't firing) sample
should take the sampler as the second argument if you want it's values available in the sampling function
- use
Cycle
- you generally want to
combine
streams with theprops
stream if they contain data you want to render - you generally want to
sample
aprops
stream with another when you want to limit activity of aprops
stream - to prevent unnecessary computation, newly-created
props
streams should have a.thru(hold)
appended to them- this holds on to the most recent value and re-emits it to other dependent streams without performing the computation that created most recent value more than once
- newly-created
props
streams might also benefit from a.skipRepeatsWith(shallowEquals)
, as this prevents props from being emitted if their top level properties are equal to the last set of props emitted- however, this can be a somewhat expensive operation, so don't overuse it
- you generally want to
remcycle
- use
remcycle
for adding state-specifc and interaction-specific functionality to Cycle components - use the
propTypes
andactionTypes
to document:- which props the component expects and their types
- however, you should ignore documenting prop types of children components
- if they are remcycle components, they can document their own prop types
- if they are React components, they can also document their own prop types
- however, you should ignore documenting prop types of children components
- which actions the component emits and their payloads' types
- you should document actions important to this component's or an ancestor component's behavior - e.g.:
- if a child action triggers a parent's state update, document the action type
- if a child action triggers a state update of the same child, don't document the action type
- you should document actions important to this component's or an ancestor component's behavior - e.g.:
- which props the component expects and their types
- use
controlled, un-controlled and semi-controlled components
- uncontrolled components
- don't maintain any of their own state - they just take in everything they'll need to render a view, and emit all interactions with the component as actions
- these are the simplest to implement, but generally aren't that useful as Cycle components - they may as well just be React components
- controlled components
- maintain their own state, using the actions they emit, and take few or no props that have anything to do with the component's state (the props they receive are purely for the view, i.e. a form label, a theme, etc)
- these are rare in general, as components usually require some configuration or manipulation by the rest of the application
- e.g. ...?
- semi-controlled components
- do a bit of both - they maintain their own state driven by their own actions, but also allow for props to be passed down that overwrite the component's state or influence it's future behaviour
- useful for stateful widgets that on occasion might need manual or initial configuration
- e.g. Select, RangeSlider, Input are the simplest kinds of these, but SingleBandAndScaleSelector and BandsAndScalesSelector are examples of semi-controlled components built on top of other, simpler semi-controlled components
- NOTE: this pattern is still being explored, as there may be some issues with overriding state automatically with
withState
- uncontrolled components
general bugs one might encounter
- 100% CPU - generally a sign that your code threw and uncaught error somewhere
- could also be because you're emitting an action that influences props, which leads to an action emission, which then influences props...
- 100% CPU - generally a sign that your code threw and uncaught error somewhere