Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Declarative Heaven with and without React.js

Declarative Heaven with and without React.js

Functional programming and other weird tips for writing readable, testable and declarative code in JavaScript and specifically React.

Avatar for Gal Schlezinger

Gal Schlezinger

March 30, 2017
Tweet

More Decks by Gal Schlezinger

Other Decks in Programming

Transcript

  1. for (var i = 10; i > 0; --i) {

    console.log(i) } MOV CX, 0Ah PRINT: INT 2H, CX LOOP
  2. Higher Order Function a function that takes a function as

    an argument or returning a function as the result ✍
  3. Higher Order Function add = a => b => a

    + b increment = add(1) increment(2) //=> 3 a function that returns a function curried function
  4. Higher Order Function apply = (fn, value) => fn(value) apply(add(1),

    2) // => 3 a function that receives a function
  5. Higher Order Function compose = (f, g) => x =>

    f(g(x))
 log = compose(
 console.log,
 e => `log: ${e}`
 )
 log(“hey”) // console: “log: hey” a function that receives a function and returns a function
  6. Array#map import {map} from ‘ramda’
 
 // map = fn

    => arr => arr.map(fn) getNames = map(e => e.name) getNames([{ name: ‘gal’ }]) // => [‘gal’]
  7. Array#map map = fn => arr => { const results

    = [] for (let i = 0; i < arr.length; i++) { const item = arr[i] const result = fn(item) results.push(result) } return results } Ramda’s / Lowdash fp’s
  8. Higher Order Component a function that takes a component as

    an argument and returning a component as the result ✍
  9. Higher Order Component const provideName = name => Component =>

    props => <Component {...props} name={name} />
  10. import React from 'react'
 const hoc = name => C

    => props => <C {...props} name={name} /> const UserName = ({name}) => <span>{name}</span> const C = hoc(‘gal’)(UserName) Our First HoC
  11. import React from 'react'
 import hoc from './hoc'
 import renderer

    from 'react-test-renderer'
 const Dummy = p => <dummy props={p} /> const render = c =>
 renderer.create(c).toJSON().props.props
 it('works', () => { const C = hoc('gal')(Dummy) expect(render(<Comp />)).toMatchSnapshot() }) Testing HoCs
  12. Higher Order Component const MyComponent = ({ name }) =>

    <span>{name}</span> const ReduxComponent = connect( state => ({ name: state.name }) )(MyComponent) Example: react-redux’s `connect`
  13. const provideName = name =>
 C =>
 props =>
 <C

    {...props} name={name} />
 const withName = provideName(‘gal’) const withReduxState = connect(mapState)
 const FinalComponent = 
 withName(
 withReduxState(
 Component
 )
 ) function composition hell
  14. const provideName = name =>
 C =>
 props =>
 <C

    {...props} name={name} />
 const withName = provideName(‘gal’) const withReduxState = connect(mapState) const FinalComponent = compose( withName, withReduxState )(Component)
  15. const UserName = ({ id }) => <Fetch url={`/api/user/${id}`}> {details

    => !details ? ( <Loading /> ) : ( <span>{details.name}</span> )} </Fetch>
  16. const FetchUser = ({ children, id }) => <Fetch url={`/api/user/${id}`}>

    {children} </Fetch> const UserName = ({ id }) => <FetchUser id={id}> {details => !details ? ( <Loading /> ) : ( <span>{details.name}</span> )} </FetchUser>
  17. class Fetch extends React.Component {
 state = {value: null}
 fetch

    = ({url}) => {
 fetch(url).then(e => e.json()).then(value =>
 this.setState({value}))
 }
 componentDidMount() {
 this.fetch(this.props)
 }
 componentWillReceiveProps(nextProps) {
 if (nextProps.url !== this.props.url) {
 this.fetch(nextProps)
 }
 }
  18. A simple trick I found for Rx Subjects $ vim

    ./BehaviorSubject.js Avoiding Lifecycle Hooks
  19. const MyComponent = ({ data }) => !data.me ? <Spinner

    /> : ( <div>{data.me.name}</div> ) graphql(gql`{ me { name } }`)(MyComponent) happens way too much
  20. THE Maybe(null).map( e => e.toUpperCase() ) // => Maybe(null) MAYBE

    FUNCTOR Maybe(“gal”).map( e => e.toUpperCase() ) // => Maybe(“GAL”)
  21. THE Maybe(null).map( e => e.toUpperCase() ).fold(e => e) // =>

    null MAYBE FUNCTOR Maybe(“gal”).map( e => e.toUpperCase() ).fold(e => e) // => “GAL”
  22. THE Maybe = a =>
 a == null || a

    == undefined
 ? Nothing()
 : Just(a)
 Nothing = () => ({
 fold: fn => null,
 map: fn => Nothing()
 })
 Just = a => ({
 fold: fn => fn(a),
 map: fn => Just(fn(a))
 }) MAYBE FUNCTOR
  23. const MyComponent = ({ Dataloader }) => <div> my name

    is <Dataloader> {d => d.me.name} </Dataloader> </div> grql(gql`{ me { name } }`)(MyComponent)
  24. const MyComponent = ({ Dataloader }) => <div> my name

    is <Dataloader spinnerType=“text”> {d => d.me.name} </Dataloader> </div> grql(gql`{ me { name } }`)(MyComponent)
  25. THE Maybe = a =>
 a == null || a

    == undefined
 ? Nothing()
 : Just(a)
 Nothing = () => ({
 fold: fn => null,
 map: fn => Nothing()
 })
 Just = a => ({
 fold: fn => fn(a),
 map: fn => Just(fn(a))
 }) MAYBE FUNCTOR
  26. THE fromNullable = a =>
 a == null || a

    == undefined
 ? Left(null)
 : Right(a)
 Left = a => ({
 fold: (l, r) => l(a),
 map: fn => Left(a)
 })
 Right = a => ({
 fold: (l, r) => r(a),
 map: fn => Right(fn(a))
 }) EITHER FUNCTOR
  27. const MyComponent = ({ Dataloader }) => <div> my name

    is <Dataloader foldLeft={e => <Error data={e} />} foldRight={d => d.me.name} /> </div> grql(gql`{ me { name } }`)(MyComponent)
  28. • Custom Components as Props • Avoiding Lifecycle with components

    and ref • Using algebraic structures (Maybe, Either) weird tips and FUN