Slide 1

Slide 1 text

Simplify Your React Component With Recompose wu_ct wuct

Slide 2

Slide 2 text

Sample Code is Here https://github.com/wuct/ recompose-f2etw

Slide 3

Slide 3 text

About Recompose • Lodash for React. • Can be used with React, Preact and all other React-like framework. • Flow typed. • 繁體中⽂文⽂文件(thanks to @neighborhood999) • I’m one of the collaborators :D

Slide 4

Slide 4 text

Why We Should use Recompose? • To write more pure functional components. • Functional programming is fun!

Slide 5

Slide 5 text

Pure Functional Component • Help prevent abuse of using setSate(). • Make code more readable. • Make testing easier.

Slide 6

Slide 6 text

Basic Functional Programming: Currying • From Wikipedia:
 Currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument. Currying is related to, but not the same as, partial application. const add = x !=> y !=> x + y add(4)(2) !// 6 addFour = add(4) addFour(2) !// 6

Slide 7

Slide 7 text

Curry in JavaScript • Because of JavaScript’s syntax, the implementation of curry in JS is usually slightly different from the origin definition. import R from 'ramda' !// Lodash implementation is equivalent. const addThreeNumbers = (x, y, z) !=> x + y + z const curriedAddThreeNumbers = R.curry(addThreeNumbers) curriedAddThreeNumbers(1, 2, 3) curriedAddThreeNumbers(1, 2)(3) curriedAddThreeNumbers(1)(2, 3) curriedAddThreeNumbers(1)(2)(3)

Slide 8

Slide 8 text

Basic Functional Programming: Function Composition • From Wikipedia:
 Function composition is an act or mechanism to combine simple functions to build more complicated ones. … the result of each function is passed as the argument of the next, and the result of the last one is the result of the whole. • In math:
 f(x) = 2x+3
 g(x) = x^2
 h = (g º f)(x)
 = g(f(x))
 = (2x + 3) ^ 2 const f = x !=> 2 * x + 3 const g = x !=> x ^ 2 const h = compose(g, f) h(2) !// 49

Slide 9

Slide 9 text

How to Implement Compose in JavaScript const compose = (!!...funcs) !=> { if (funcs.length !!=== 0) { return arg !=> arg } if (funcs.length !!=== 1) { return funcs[0] } return funcs.reduce((a, b) !=> (!!...args) !=> a(b(!!...args))) }

Slide 10

Slide 10 text

Basic Functional Programming: Higher-order Function • From Wikipedia:
 A function that does at least one of the following:
 1. Takes one or more functions as arguments.
 2. Returns a function as its result. • Example: curry(), compose()

Slide 11

Slide 11 text

Now We Get All The Tools to Have Fun !// map() and filter() are HOFs const map = fun !=> array !=> array.map(fun) const filter = fun !=> array !=> array.filter(fun) const increaseAll = map(x !=> x + 1) const takeEven = filter(x !=> x % 2 !!=== 0) const increaseAllAndTakeEven = compose( takeEven, increaseAll ) increaseAllAndTakeEven([1, 2, 3, 4, 5]) !// [2, 4, 6]

Slide 12

Slide 12 text

Higher-order Component • A function that does at least one of the following:
 1. Takes one or more components as arguments.
 2. Returns a component as its result. • Remember that, in React, functions can also be components (a.k.a. pure functional component). • Example: • react-redux’ connect() • styled-components’ withTheme() • react-router’s withRouter() • react-apollo’s graphql() • Most of functions in Recompose

Slide 13

Slide 13 text

import * as Rc from 'recompose' !// enhance is a HOC, which is a function accepting !// a component and return a new component with the !// “MyAwesomeButton" display name. const enhance = Rc.setDisplayName('MyAwesomeButton') const MyAwesomeButton = (!!...props) !=> This is awesome!! export default enhance(MyAwesomeButton) setDisplayName( displayName: string ): HigherOrderComponent

Slide 14

Slide 14 text

Some Commonly Used HOCs • pure • mapProps • withState • withHandlers • withStateHandlers

Slide 15

Slide 15 text

const enhance = Rc.pure const MyComponent = () !=>
{!/* !!... !*/}!
export default enhance(MyComponent) pure() pure: HigherOrderComponent

Slide 16

Slide 16 text

const enhance = Rc.mapProps(({ firstName, secondName }) !=> ({ name: firstName + ' ' + secondName })) const Name = ({ name }) !=> {name}! export default enhance(Name) mapProps( propsMapper: (ownerProps: Object) => Object, ): HigherOrderComponent

Slide 17

Slide 17 text

const enhance = Rc.withState('count', 'setCount', 0) const MyComponent = ({ count, setCount }) !=>
setCount(count + 1)}> Click {count} {count > 1 ? 'times' : 'time'}. !
export default enhance(MyComponent) withState( stateName: string, stateUpdaterName: string, initialState: any | (props: Object) => any ): HigherOrderComponent

Slide 18

Slide 18 text

const enhance = Rc.compose( Rc.withState('count', 'setCount', 0), Rc.withHandlers({ onClick: ({ count, setCount }) !=> () !=> setCount(count + 1) }) ) const MyComponent = ({ count, onClick }) !=>
Click {count} {count > 1 ? 'times' : 'time'}. !
export default enhance(MyComponent) withHandlers( handlerCreators: { [handlerName: string]: (props: Object) => Function } | handlerCreatorsFactory: (initialProps) => { [handlerName: string]: (props: Object) => Function } ): HigherOrderComponent

Slide 19

Slide 19 text

const enhance = Rc.withStateHandlers({ count: 0 }, { onClick: ({ count }) !=> () !=> ({ count: count + 1 }) }) const MyComponent = ({ count, onClick }) !=>
Click {count} {count > 1 ? 'times' : 'time'}. !
export default enhance(MyComponent) withStateHandlers( initialState: Object | (props: Object) => any, stateUpdaters: { [key: string]: (state:Object, props:Object) => (...payload: any[]) => Object } )

Slide 20

Slide 20 text

Usage With Redux export default Rc.compose( connect( ({ address }) !=> ({ address }), { submitAddress }, ), Rc.withStateHandlers( ({ address }) !=> ({ address }), { onChange: () !=> e !=> ({ address: e.target.value }), onSubmit: ({ address }, { submitAddress }) !=> e !=> { e.preventDefault() submitAddress(address) } } ), Rc.pure )(({ address, onChange, onSubmit }) !=> Submit! ! )

Slide 21

Slide 21 text

Usage With Apollo export default Rc.compose( Rc.withStateHandlers({ keyword: '' }, { onChange: () !=> e !=> ({ keyword: e.target.value }), }), graphql(gql` query HotelSearchQuery($keyword: String!) { hotels(keyword: $keyword) { !!... } }`, { options: ({ keyword }) !=> ({ variables: { keyword }}), }), mapProps(({ data, !!...otherProps }) !=> ({ !!...otherProps, !!...data, })), Rc.pure, )(({ keyword, onChange, hotels }) !=>
    {hotels.map(!/* !!... !*/)}!
!
)

Slide 22

Slide 22 text

Usage With React Router export default Rc.compose( withRouter, Rc.mapProps(({ match: { params = {} }}) !=> ({ keyword: params.keyword, })), graphql(gql` !!... `, { options: ({ keyword }) !=> ({ variables: { keyword }}), }), Rc.pure )(({ hotels }) !=>
    {hotels.map(!/* !!... !*/)}!
!
)

Slide 23

Slide 23 text

Usage With Observable mapPropsStream( ownerPropsToChildProps: (props$: Observable) => Observable, BaseComponent: ReactElementType ): ReactComponent Rc.mapPropsStream(props$ !=> { const value$ = new BehaviorSubject('') const onClick = e !=> value$.next(e.target.value) return props$.combineLatest( value$.distinctUntilChanged(), (props, value) !=> ({ !!...props, value, onChange }) ) })(({ value, onChange }) !=> )

Slide 24

Slide 24 text

Question? • What is createEagerElement? • Why not add XXX to Recompose?