Refract
  • Read Me
  • Introduction
    • Why Refract?
    • Core Concepts
    • Thinking In Refract
    • Alternatives
  • Usage
    • Getting Started
    • Installation
    • Connecting To React
    • Observing React, Preact and Inferno
    • Injecting Dependencies
    • Observing Redux
    • Observing Anything
    • Handling Effects
    • Pushing to Props
    • Rendering Components
    • Handling Errors
    • Testing
  • Recipes
    • Dependency Injection
    • Creating An API Dependency
    • Handling state
    • Replacing Redux Connect
  • Examples
    • Debounced fetch
    • Counter
    • Field validation
    • Redux fetch
    • Routing
    • Typeahead
    • Visit time
  • API
    • compose
    • withEffects
    • toProps, asProps
    • useRefract
    • refractEnhancer (Redux)
  • Glossary
  • Feedback
Powered by GitBook
On this page
  • Mapping state to props
  • Mapping action creators to props
  • Merging props
  1. Recipes

Replacing Redux Connect

PreviousHandling stateNextExamples

Last updated 6 years ago

It is possible to in Refract, and Refract enables you to : as a result, we can easily and reactively map any data source to props with Refract.

This recipe will show you how you can replace connect from the react-redux package using Refract. The syntax is not as compact as connect, but it has several benefits:

  • You have full control over when children are rendered: the required selectors don't have to be re-computed every single time or loaded upfront (you can lazy load selectors)

  • You can leverage Refract to handle other effects (network requests, analytics, etc.)

  • You can mix it with other data sources (props, other external sources)

We recommend you look at and if you haven't already.

connect takes three arguments (mapStateToProps, mapDispatchToProps, mergeProps) and we are going to go through how to replace each of them.

Mapping state to props

Given that we have a Redux store available in our props (see ) and that we have added the Refract store enhancer, we can observe selectors and map their output to props:

import { combineLatest } from 'rxjs'
import { map } from 'rxjs/operators'
import { withEffects, toProps } from 'refract-rxjs'
import { getUser, getPosts } from './mySelectors'

const aperture = (component, initialProps) => {
    const { store } = initialProps

    const user$ = store.observe(getUser)
    const posts$ = store.observe(getPosts)

    return combineLatest(users$, posts$).pipe(
        map(([user, posts]) => ({
            user,
            posts
        })),
        map(toProps)
    )
}

const ContainerComponent = withEffects(aperture)(BaseComponent)

Let's look at the example above step by step:

  • We create two streams (user$, posts$) from two selectors (getUser, getPosts)

  • We combine these two streams into another stream where:

    • We create an object containing users and posts ({ user, posts })

    • We pass each object to our component's props (with toProps)

The result is the same as connect: users and posts will be added to our component's props. The Refract way is more verbose in some cases, but there are a few things which can be leveraged from reactive programming:

  • Selective updates: you can choose when to listen to selectors

    • We might only be interested in getting the first user value: const user$ = store.observe(getUser).pipe(take(1))

    • We might want to only get posts per user

    const posts$ = store.observe(getUser).pipe(
        map(user => user ? user.id : null),
        distinctUntilChanged(),
        switchMap(userId => userId ? store.observe(getPosts(userId)) : empty())
    )

Mapping action creators to props

Replacing mapDispatchToProps can be done in different ways. A first way would be to do it exactly like connect by binding dispatch to each action creator and pushing them to props using toProps.

Instead, we are going to look at a different way: dispatching is imperative and can be seen as a side-effect, so we are going to treat it as such and move its use to an effect handler. We push event callbacks to our component (using pushEvent), observe them, pass their values to their respective action creators and send the whole lot to be dispatched.

import { withEffects, toProps } from 'refract-rxjs'
import { of, merge } from 'rxjs'
import { map } from 'rxjs/operators'
import { createAddPostAction, createRemovePostAction } from './actions'

const handler = initialProps => effect => {
    const { store } = initialProps

    if (effect.type === 'DISPATCH') {
        store.dispatch(effect.payload)
    }
}

const toDispatch = action => ({
    type: 'DISPATCH',
    payload: action
})

const aperture = component => {
    const [ addPostEvents$, addPost] = component.pushEvent('addPost')
    const [ removePostEvents$, removePost] = component.pushEvent('removePost')

    return merge(
        of({
            addPost,
            removePost
        }).pipe(map(toProps)),

        merge(
            addPostEvents$.pipe(map(createAddPostAction)),
            removePostEvents$.pipe(map(createRemovePostAction))
        ).pipe(map(toDispatch))
    })
}

const ContainerComponent = withEffects(aperture, { handler })(BaseComponent)

Again, it is a more verbose approach than mapDispatchToProps. But by separating action creation from dispatching logic, it enables you to hook other side-effects that you could otherwise find in a Redux middleware (like analytics events).

Merging props

Due to the point above, you no longer need to use thunks inside mapStateToProps and you no longer to use memoized selectors (using ): dependencies of a selector can be expressed using streams.

The third less-known argument of connect is mergeProps: it takes the component's props, the outputs of mapStateToProps and mapDispatchToProps, and merges them together (by default). It would typically be used for preventing some component's props to be passed down, or to perform extra computations. This is no longer needed, since you can map or replace props in Refract: see .

handle local state
observe any data source
Installation
Observing Redux
Injecting Dependencies
reselect
Pusing to props