Share
Embed
Transcript
33 slides
-
Disclaimer. (You will probably not need a couple of things
presented here) -
The goal of this talk is to present Composition
on React Components. -
The goal of this talk is to present Composition
on React Components. • Fast introduction to HOC • Composition on real world • Extra: Recompose library -
class CommentList extends React.Component { constructor(props) { super(props); this.state =
{ comments: DataSource.getComments() }; } render() { return ( <div> {this.state.comments.map((comment) => ( <Comment comment={comment} key={comment.id} /> ))} </div> ); } } -
class BlogPost extends React.Component { constructor(props) { super(props); this.state =
{ blogPost: DataSource.getBlogPost(props.id) }; } render() { return <TextBlock text={this.state.blogPost} />; } } -
const CommentListWithSubscription = withSubscription( CommentList, (DataSource) => DataSource.getComments() ); const
BlogPostWithSubscription = withSubscription( BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id) ); -
import { Shake } from 'react-motions' const ComponentWithShake = ()
=> ( <Shake> <React.Fragment> Shake your booty, shake your booty </React.Fragment> </Shake> ) -
import { withShake } from 'react-motions' const ComponentWithShake = ()
=> withShake( <React.Fragment> Shake your booty, shake your booty </React.Fragment> ) -
import { Bounce } from 'react-motions' const DoNotStopBouncing = ()
=> ( <Bounce infinite> <React.Fragment>Bouncing…</React.Fragment> </Bounce> ) -
import { withBounce, withInfinite } from 'react-motions' const DoNotStopBouncing =
withInfinite( withBounce( <React.Fragment>Bouncing…</React.Fragment> ) ) -
import { withBounce, withShake, withInfinite, withSequence } from
'react-motions' const Component = <div>How can I look beautiful</div> const ComponentWithShake = withShake(Component) const ComponentWithShakeAndBounce = withShake(withBounce(Component)) const ComponentWithInfiniteBounce = withInfinite(withBounce(Component)) const ComponentWithShakeThenBounce = withSequence(withShake(withBounce(Component))) Recap -
import { withBounce, withShake, withInfinite, withSequence } from
'react-motions' const Component = <div>How can I look beautiful</div> const ComponentWithShake = withShake(Component) const ComponentWithShakeAndBounce = withShake(withBounce(Component)) const ComponentWithInfiniteBounce = withInfinite(withBounce(Component)) const ComponentWithShakeThenBounce = withSequence(withShake(withBounce(Component))) -
import { withBounce, withShake, withInfinite, withSequence } from
'react-motions' const Component = <div>How can I look beautiful</div> const ComponentWithShake = withShake(Component) const ComponentWithShakeAndBounce = withShake(withBounce(Component)) const ComponentWithInfiniteBounce = withInfinite(withBounce(Component)) const ComponentWithShakeThenBounce = withSequence(withShake(withBounce(Component))) -
import { withBounce, withShake, withInfinite, withSequence } from
'react-motions' const Component = <div>How can I look beautiful</div> const ComponentWithShake = withShake(Component) const ComponentWithShakeAndBounce = withShake(withBounce(Component)) const ComponentWithInfiniteBounce = withInfinite(withBounce(Component)) const ComponentWithShakeThenBounce = withSequence(withShake(withBounce(Component))) -
const Component = () => ( withInfinite( withFadeOut( withInfinite( withShake(
<h2>Bouncing and Fading Out infinitely!!</h2> ) ) ) ) ) -
import { withState, enhance } from ‘recompose' const enhance
= withState('counter', 'setCounter', 0) const Counter = enhance(({ counter, setCounter }) => <React.Fragment> Count: {counter} <button onClick={() => setCounter(n => n + 1)}>Increment</button> <button onClick={() => setCounter(n => n - 1)}>Decrement</button> </React.Fragment> ) -
import { branch, enhance, renderComponent } from ‘recompose' //
`isLoading()` is a function that returns whether or not the component // is in a loading state const spinnerWhileLoading = isLoading => branch( isLoading, renderComponent(Spinner) // `Spinner` is a React component ) // Now use the `spinnerWhileLoading()` helper to add a loading spinner to any // base component const enhance = spinnerWhileLoading( props => !(props.title && props.author && props.content) ) const Post = enhance(({ title, author, content }) => <article> <h1>{title}</h1> <h2>By {author.name}</h2> <div>{content}</div> </article> ) -
// A component that is expensive to render const ExpensiveComponent
= ({ propA, propB }) => {...} // Optimized version of same component, using shallow comparison of props // Same effect as extending React.PureComponent const OptimizedComponent = pure(ExpensiveComponent) // Even more optimized: only updates if specific prop keys have changed const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent) -
const enhance = compose( // This is a Recompose-friendly version
of Relay.createContainer(), provided by recompose-relay createContainer({ fragments: { post: () => Relay.QL` fragment on Post { title, content } ` } }), flattenProp('post') ) const Post = enhance(({ title, content }) => <article> <h1>{title}</h1> <div>{content}</div> </article> ) -
// Any Recompose module can be imported individually import getDisplayName
from 'recompose/getDisplayName' ConnectedComponent.displayName = `connect(${getDisplayName(BaseComponent)})` // Or, even better: import wrapDisplayName from 'recompose/wrapDisplayName' ConnectedComponent.displayName = wrapDisplayName(BaseComponent, 'connect') import toClass from 'recompose/toClass' // Converts a function component to a class component, e.g. so it can be given // a ref. Returns class components as is. const ClassComponent = toClass(FunctionComponent)