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

Recompose to simplicity and beyond

Recompose to simplicity and beyond

A presentation about the basics of HoC, Presentational Layers, Container Components, but mostly recompose and how to structure projects in a more functional way.

Avatar for Timo Obereder

Timo Obereder

June 22, 2017
Tweet

More Decks by Timo Obereder

Other Decks in Programming

Transcript

  1. RECOMPOSE To Simplicity And Beyond 22.June 2017 – React JS

    Meetup Vienna Timo Obereder Android Native-/React Web- Developer @defuex
  2. Application: The process of applying a function to its arguments

    in order to produce a return value. Partial Application: The process of applying a function to some of its arguments. It takes a function with multiple parameters and returns a function with fewer parameters. Add(x,y) = x + y Add2 = Partial(Add, 7)
  3. Curry: A function that takes a function with multiple parameters

    as input and returns a function with exactly one parameter. f(x,y,z) curried to f:x => (y => (z => n)))
  4. react-redux (arg1, arg2) => (Component) => EnhancedComponent const EnhancedComponent =

    connect( mapStateToProps, mapDispatchToProps, )(Component);
  5. (Component, arg1) => EnhancedComponent relay export default Relay.createContainer(Todo, { fragments:

    { todo: () => Relay.QL` fragment on Todo { complete, id, text }` } });
  6. Yes

  7. But

  8. const Commit = ({ sha, message }) => ( <div>

    <p>{sha}</p> <p>{message}</p> </div> )
  9. class CommitContainer extends React.Component { state = { commit: null

    }; componentDidMount() { fetch(`/commits/${this.props.id}`) .then(commit => this.setState({ commit })); } render() { const { commit } = this.state; return <Commit {...this.props} {...commit} />; } }
  10. const fetchCommit = (WrappedComponent) => ( class extends React.Component {

    state = { commit: null }; componentDidMount() { fetch(`/commits/${this.props.id}`) .then(commit => this.setState({ commit })); } render() { const { commit } = this.state; return <WrappedComponent {...this.props} {...commit} />; } } ) const CommitContainer = fetchCommit(Commit);
  11. const fetchResource = (path) => (WrappedComponent) => ( class extends

    React.Component { state = { resource: null }; componentDidMount() { path(this.props) .then(resource => this.setState({ resource })); } render() { const { resource } = this.state; return <WrappedComponent {...this.props} {...resource} />; } } ) const fetchPost = fetchResource(props => fetch(`/commits/${props.id}`)); const CommitContainer = fetchPost(Commit);
  12. Props Proxy const withUser = (WrappedComponent) => { return class

    extends React.Component { render() { const user = { id: ’1337', name: Pacman' }; return ( <WrappedComponent {...this.props} user={user} /> ); } } } <Props manipulation>
  13. Inheritance Inversion <Render hijacking> function authLocked(WrappedComponent) { return class Enhancer

    extends WrappedComponent { render() { if (this.props.loggedIn) { return super.render() } else { return null } } } }
  14. Inheritance Inversion <State manipulation> export function debug(WrappedComponent) { return class

    Enhancer extends WrappedComponent { render() { return ( <div> <h2>Debugger Component</h2> <p>Props</p> <pre>{JSON.stringify(this.props, null, 2)}</pre> <p>State</p><pre>{JSON.stringify(this.state, null, 2)}</pre> {super.render()} </div> ) } } }
  15. const BaseComponent = (props) => {...} let EnhancedComponent = firstHoc(BaseComponent);

    EnhancedComponent = secondHoc(/*...args*/)(EnhancedComponent); EnhancedComponent = thirdHoc(/*...args*/)(EnhancedComponent);
  16. function compose(...funcs) { if (funcs.length === 0) { return arg

    => arg } if (funcs.length === 1) { return funcs[0] } const last = funcs[funcs.length - 1] return (...args) => { let result = last(...args) for (let i = funcs.length - 2; i >= 0; i--) { const f = funcs[i] result = f(result) } return result } }
  17. „recompose is a react utility belt for function components and

    higher-order components“ – Andrew Clark
  18. const withCounterState = withState('counter', 'setCounter', 0) const Counter = ({

    counter, setCounter, }) => ( <div> Count: {counter} <button onClick={() => setCounter(n => n + 1)}>Increment</button> <button onClick={() => setCounter(n => n - 1)}>Decrement</button> </div> ) export default compose( withCounterState, )(Counter); withState
  19. withHandlers const withCounterHandler = withHandlers({ handleCounterUp : ({ counter, setCounter,

    }) => () => { setCounter(counter + 1); }, handleCounterDown : ({ counter, setCounter, }) => () => { setCounter(counter - 1); }, });
  20. withState & withHandlers const Counter = ({ counter, handleCounterUp, handleCounterDown,

    }) => ( <div> Count: {counter} <button onClick={handleCounterUp}>Increment</button> <button onClick={handleCounterDown}>Decrement</button> </div> ) export default compose( withCounterState, withCounterHandler, )(Counter);
  21. shouldUpdate const withCommitsAmountChanged = shouldUpdate( (props, nextProps) => { if(

    (props.commitsMax !== nextProps.commitsMax) || (props.someOtherProp !== nextProps.someOtherProp) ){ return true; } return false; });
  22. Cons Expensive to change if abstraction is wrong Could be

    complex for newcomers(pretty functional) „More complex computation"