Skip to content

Commit

Permalink
Migrate to createAction (#110)
Browse files Browse the repository at this point in the history
This PR migrates most actions over to `createAction`. The goal of this is
1. Better typescript support using `.match` which allows us to use a [typescript guard](https://redux-toolkit.js.org/api/createAction#as-a-typescript-type-guard)
2. Easier for users. We previously exposed the const to the user so that they can createAction themselves before using it in a slice. Now they can just import it. For example:

```js
import { createSlice } from '@reduxjs/toolkit'
import { saveResponse, beforeVisit } from '@thoughtbot/superglue'

export const flashSlice = createSlice({
  name: 'flash',
  initialState: {},
  extraReducers: (builder) => {
    builder.addCase(beforeVisit, (state, action) => {
      return {}
    })
    builder.addCase(saveResponse, (state, action) => {
      const { page } = action.payload;

      return {
        ...state, ...page.slices.flash
      }
    })
  }
})

```
  • Loading branch information
jho406 authored Oct 10, 2024
1 parent 8600601 commit 38e3d6e
Show file tree
Hide file tree
Showing 18 changed files with 214 additions and 402 deletions.
73 changes: 7 additions & 66 deletions superglue/lib/action_creators/index.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,24 @@
import { urlToPageKey, getIn } from '../utils'
import parse from 'url-parse'
import {
SAVE_RESPONSE,
HANDLE_GRAFT,
saveResponse,
GRAFTING_ERROR,
GRAFTING_SUCCESS,
COPY_PAGE,
UPDATE_FRAGMENTS,
updateFragments,
handleGraft,
} from '../actions'
import { remote } from './requests'
import {
CopyAction,
VisitResponse,
SaveResponseAction,
UpdateFragmentsAction,
SaveAndProcessPageThunk,
DefermentThunk,
HandleGraftAction,
GraftResponse,
Page,
Defer,
JSONMappable,
} from '../types'
export * from './requests'

export function copyPage({
from,
to,
}: {
from: string
to: string
}): CopyAction {
return {
type: COPY_PAGE,
payload: {
from,
to,
},
}
}

export function saveResponse({
pageKey,
page,
}: {
pageKey: string
page: VisitResponse
}): SaveResponseAction {
pageKey = urlToPageKey(pageKey)

return {
type: SAVE_RESPONSE,
payload: {
pageKey,
page,
},
}
}

export function handleGraft({
pageKey,
page,
}: {
pageKey: string
page: GraftResponse
}): HandleGraftAction {
pageKey = urlToPageKey(pageKey)

return {
type: HANDLE_GRAFT,
payload: {
pageKey,
page,
},
}
}

function fetchDeferments(
pageKey: string,
defers: Defer[] = []
Expand Down Expand Up @@ -122,7 +65,7 @@ function fetchDeferments(
}
}

function updateFragmentsUsing(page: Page): UpdateFragmentsAction {
function getChangedFragments(page: Page) {
const changedFragments: Record<string, JSONMappable> = {}
page.fragments.forEach((fragment) => {
const { type, path } = fragment
Expand All @@ -131,10 +74,7 @@ function updateFragmentsUsing(page: Page): UpdateFragmentsAction {
changedFragments[type] = getIn(page, path) as JSONMappable
})

return {
type: UPDATE_FRAGMENTS,
payload: { changedFragments },
}
return changedFragments
}

export function saveAndProcessPage(
Expand All @@ -157,7 +97,8 @@ export function saveAndProcessPage(
return dispatch(fetchDeferments(pageKey, defers)).then(() => {
if (page.fragments.length > 0) {
const finishedPage = getState().pages[pageKey]
dispatch(updateFragmentsUsing(finishedPage))
const changedFragments = getChangedFragments(finishedPage)
dispatch(updateFragments({ changedFragments }))
return Promise.resolve()
}
})
Expand Down
53 changes: 7 additions & 46 deletions superglue/lib/action_creators/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,15 @@ import {
removePropsAt,
} from '../utils'
import {
BEFORE_FETCH,
BEFORE_VISIT,
BEFORE_REMOTE,
SUPERGLUE_ERROR,
beforeFetch,
beforeVisit,
beforeRemote,
copyPage,
superglueError,
} from '../actions'
import { copyPage, saveAndProcessPage } from './index'
import { saveAndProcessPage } from './index'
import {
BeforeVisit,
BeforeFetch,
FetchArgs,
BeforeRemote,
HandleError,
VisitResponse,
PageResponse,
Page,
Expand All @@ -30,48 +27,12 @@ import {
VisitCreator,
} from '../types'

function beforeVisit(payload: {
fetchArgs: FetchArgs
currentPageKey: string
}): BeforeVisit {
return {
type: BEFORE_VISIT,
payload,
}
}

function beforeRemote(payload: {
fetchArgs: FetchArgs
currentPageKey: string
}): BeforeRemote {
return {
type: BEFORE_REMOTE,
payload,
}
}

function beforeFetch(payload: { fetchArgs: FetchArgs }): BeforeFetch {
return {
type: BEFORE_FETCH,
payload,
}
}

function handleError(err: Error): HandleError {
return {
type: SUPERGLUE_ERROR,
payload: {
message: err.message,
},
}
}

function handleFetchErr(
err: Error,
fetchArgs: FetchArgs,
dispatch: Dispatch
): never {
dispatch(handleError(err))
dispatch(superglueError({ message: err.message }))
throw err
}

Expand Down
88 changes: 76 additions & 12 deletions superglue/lib/actions.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,80 @@
export const BEFORE_FETCH = '@@superglue/BEFORE_FETCH'
export const BEFORE_VISIT = '@@superglue/BEFORE_VISIT'
export const BEFORE_REMOTE = '@@superglue/BEFORE_REMOTE'
import { createAction } from '@reduxjs/toolkit'
import {
FetchArgs,
PageKey,
JSONValue,
GraftResponse,
VisitResponse,
} from './types'
import { urlToPageKey } from './utils'

export const SAVE_RESPONSE = '@@superglue/SAVE_RESPONSE'
export const HANDLE_GRAFT = '@@superglue/HANDLE_GRAFT'

export const SUPERGLUE_ERROR = '@@superglue/ERROR'
export const GRAFTING_ERROR = '@@superglue/GRAFTING_ERROR'
export const GRAFTING_SUCCESS = '@@superglue/GRAFTING_SUCCESS'

export const HISTORY_CHANGE = '@@superglue/HISTORY_CHANGE'
export const SET_CSRF_TOKEN = '@@superglue/SET_CSRF_TOKEN'
export const REMOVE_PAGE = '@@superglue/REMOVE_PAGE'
export const COPY_PAGE = '@@superglue/COPY_PAGE'
export const UPDATE_FRAGMENTS = '@@superglue/UPDATE_FRAGMENTS'
export const saveResponse = createAction(
'@@superglue/SAVE_RESPONSE',
({ pageKey, page }: { pageKey: string; page: VisitResponse }) => {
pageKey = urlToPageKey(pageKey)

return {
payload: {
pageKey,
page,
},
}
}
)

export const handleGraft = createAction(
'@@superglue/HANDLE_GRAFT',
({ pageKey, page }: { pageKey: string; page: GraftResponse }) => {
pageKey = urlToPageKey(pageKey)

return {
payload: {
page,
pageKey,
},
}
}
)

export const superglueError = createAction<{ message: string }>(
'@@superglue/ERROR'
)

export const updateFragments = createAction<{
changedFragments: Record<string, JSONValue>
}>('@@superglue/UPDATE_FRAGMENTS')

export const copyPage = createAction<{ from: PageKey; to: PageKey }>(
'@@superglue/COPY_PAGE'
)

export const removePage = createAction<{ pageKey: PageKey }>(
'@@superglue/REMOVE_PAGE'
)

export const beforeFetch = createAction<{ fetchArgs: FetchArgs }>(
'@@superglue/BEFORE_FETCH'
)

export const beforeVisit = createAction<{
currentPageKey: PageKey
fetchArgs: FetchArgs
}>('@@superglue/BEFORE_VISIT')

export const beforeRemote = createAction<{
currentPageKey: PageKey
fetchArgs: FetchArgs
}>('@@superglue/BEFORE_REMOTE')

export const setCSRFToken = createAction<{
csrfToken: string | undefined
}>('@@superglue/SET_CSRF_TOKEN')

export const historyChange = createAction<{
pathname: string
search: string
hash: string
}>('@@superglue/HISTORY_CHANGE')
20 changes: 9 additions & 11 deletions superglue/lib/components/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react'
import { urlToPageKey, pathWithoutBZParams } from '../utils'
import { REMOVE_PAGE, HISTORY_CHANGE } from '../actions'
import { removePage, historyChange } from '../actions'
import {
HistoryState,
Keypath,
Expand Down Expand Up @@ -142,12 +142,7 @@ class Nav extends React.Component<Props, State> {
this.scrollTo(0, 0)

if (action === 'replace' && prevPageKey && prevPageKey !== nextPageKey) {
store.dispatch({
type: REMOVE_PAGE,
payload: {
pageKey: prevPageKey,
},
})
store.dispatch(removePage({ pageKey: prevPageKey }))
}

return true
Expand Down Expand Up @@ -178,10 +173,13 @@ class Nav extends React.Component<Props, State> {
const state = location.state as HistoryState

if (state && 'superglue' in state) {
store.dispatch({
type: HISTORY_CHANGE,
payload: { pathname, search, hash },
})
store.dispatch(
historyChange({
pathname,
search,
hash,
})
)

if (action !== 'POP') {
return
Expand Down
28 changes: 13 additions & 15 deletions superglue/lib/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { rootReducer } from './reducers'
import { config } from './config'
import { urlToPageKey, ujsHandlers, argsForHistory } from './utils'
import { saveAndProcessPage } from './action_creators'
import { HISTORY_CHANGE, SET_CSRF_TOKEN } from './actions'
import { historyChange, setCSRFToken } from './actions'
import { ConnectedComponent, Provider, connect } from 'react-redux'

import {
Expand All @@ -17,16 +17,15 @@ import {
import Nav from './components/Nav'

export {
BEFORE_FETCH,
BEFORE_VISIT,
BEFORE_REMOTE,
SAVE_RESPONSE,
UPDATE_FRAGMENTS,
COPY_PAGE,
REMOVE_PAGE,
beforeFetch,
beforeVisit,
beforeRemote,
saveResponse,
updateFragments,
copyPage,
removePage,
GRAFTING_ERROR,
GRAFTING_SUCCESS,
HISTORY_CHANGE,
} from './actions'

import { mapStateToProps, mapDispatchToProps } from './utils/react'
Expand Down Expand Up @@ -81,16 +80,15 @@ function start({
return {
reducer: rootReducer,
prepareStore: function (store: SuperglueStore) {
store.dispatch({
type: HISTORY_CHANGE,
payload: {
store.dispatch(
historyChange({
pathname: location.pathname,
search: location.query,
hash: location.hash,
},
})
})
)
store.dispatch(saveAndProcessPage(initialPageKey, initialPage))
store.dispatch({ type: SET_CSRF_TOKEN, payload: { csrfToken } })
store.dispatch(setCSRFToken({ csrfToken }))
},
initialState: pageToInitialState(initialPageKey, initialPage),
initialPageKey,
Expand Down
7 changes: 1 addition & 6 deletions superglue/lib/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,7 @@ const fragmentMiddleware: Middleware<unknown, RootState, Dispatch> =
return nextAction
}

store.dispatch({
type: actions.UPDATE_FRAGMENTS,
payload: {
changedFragments,
},
})
store.dispatch(actions.updateFragments({ changedFragments }))

return nextAction
}
Expand Down
Loading

0 comments on commit 38e3d6e

Please sign in to comment.