Widgets written in Cycle.js and Remcycle


0.1.312 months ago3 years agoMinified + gzip package size for @descarteslabs/cycle-widgets in KB



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's shouldUpdate or pure 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)
  • styling, CSS

    • use styled.div and styled.span from styled-components in place of divs, spans, 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 or 100% 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
  • 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
  • Cycle

    • you generally want to combine streams with the props stream if they contain data you want to render
    • you generally want to sample a props stream with another when you want to limit activity of a props 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
  • remcycle

    • use remcycle for adding state-specifc and interaction-specific functionality to Cycle components
    • use the propTypes and actionTypes 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
      • 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
  • 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
  • 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...

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.