Skip to content

Commit

Permalink
update to use react-redux hooks
Browse files Browse the repository at this point in the history
tweaks dataKey function
  • Loading branch information
ruanyl committed Mar 3, 2020
1 parent 30d6f5e commit 6484b58
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 97 deletions.
1 change: 1 addition & 0 deletions __test__/dataloader.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// TODO
describe('test', () => {
it('should be true', function() {
expect(true).toBe(true)
Expand Down
7 changes: 6 additions & 1 deletion example/app.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { App } from 'reapex'
import { createLogger } from 'redux-logger'

import dataloaderPlugin from '../src'

const app = new App()
const logger = createLogger({
stateTransformer: (state: any) => state.toJS(),
})

const app = new App({ middlewares: [logger] })

export const { mutations, load, model, useDataLoader } = app.plugin(
dataloaderPlugin
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"@types/jest": "^24.0.23",
"@types/react": "^16.8.6",
"@types/react-dom": "^16.8.6",
"@types/react-redux": "^5.0.19",
"@types/react-redux": "^7.1.7",
"@types/redux-logger": "^3.0.7",
"ajv": "~6.9.1",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.15.1",
Expand All @@ -38,10 +39,11 @@
"prettier": "^1.19.1",
"react": "~16.8.6",
"react-dom": "~16.8.6",
"react-redux": "~5.1.0",
"react-redux": "~7.2.0",
"reapex": "0.10.0",
"redux": "^4.0.0",
"redux-devtools-extension": "^2.13.8",
"redux-logger": "^3.0.6",
"redux-saga": "^1.1.0",
"reselect": "^4.0.0",
"ts-jest": "^24.2.0",
Expand Down
31 changes: 13 additions & 18 deletions src/DataLoader.mutations.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { State } from 'reapex'

import {
Meta,
DataLoaderState,
LoaderData,
LoaderStatus,
DataLoaderState,
Meta,
} from './dataloader.types'

export const init = (meta: Meta) => (s: State<{ data: LoaderData }>) => {
const name = meta.name
const key = meta.dataKey(name, meta.params)
const updated = update(name, key, s.data, {
const key = meta.dataKey(meta.name, meta.params)
const updated = update(key, s.data, {
data: null,
loading: false,
error: null,
Expand All @@ -18,17 +18,15 @@ export const init = (meta: Meta) => (s: State<{ data: LoaderData }>) => {
}

export const start = (meta: Meta) => (s: State<DataLoaderState>) => {
const name = meta.name
const key = meta.dataKey(name, meta.params)
const updated = update(name, key, s.data, { loading: true })
const key = meta.dataKey(meta.name, meta.params)
const updated = update(key, s.data, { loading: true })
return s.set('data', updated)
}

export const loadSuccess = (meta: Meta, data: any, isFresh: boolean) => (
s: State<DataLoaderState>
) => {
const name = meta.name
const key = meta.dataKey(name, meta.params)
const key = meta.dataKey(meta.name, meta.params)

let status: Partial<LoaderStatus> = {
data,
Expand All @@ -43,17 +41,16 @@ export const loadSuccess = (meta: Meta, data: any, isFresh: boolean) => (
}
}

const updated = update(name, key, s.data, status)
const updated = update(key, s.data, status)
return s.set('data', updated)
}

export const loadFailure = (meta: Meta, error: Error) => (
s: State<DataLoaderState>
) => {
const name = meta.name
const key = meta.dataKey(name, meta.params)
const key = meta.dataKey(meta.name, meta.params)

const updated = update(name, key, s.data, {
const updated = update(key, s.data, {
error,
loading: false,
lastErrorTime: Date.now(),
Expand All @@ -62,13 +59,11 @@ export const loadFailure = (meta: Meta, error: Error) => (
}

function update(
name: string,
key: string,
state: LoaderData,
data: Partial<LoaderStatus>
): LoaderData {
const id = `${name}/${key}`
let dataStorage = state[id]
let dataStorage = state[key]
// initialize with default values if data NOT exist
if (!dataStorage) {
dataStorage = {
Expand All @@ -84,5 +79,5 @@ function update(
...data,
}

return { ...state, [id]: dataStorage }
return { ...state, [key]: dataStorage }
}
65 changes: 21 additions & 44 deletions src/dataloader.plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect, useState } from 'react'
import { App, GlobalState } from 'reapex'
import { useCallback, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { App } from 'reapex'
import { SagaIterator, Task } from 'redux-saga'
import { call, cancel, delay, fork, put, select } from 'redux-saga/effects'

Expand Down Expand Up @@ -29,7 +30,7 @@ const defaultProps: OptionalProps = {
params: undefined,
dataPersister: undefined,
lazyLoad: false,
dataKey: () => 'default',
dataKey: defaultDataKeyFunc,
}

const plugin = (app: App, namespace: string = '@@dataloader') => {
Expand Down Expand Up @@ -72,13 +73,11 @@ const plugin = (app: App, namespace: string = '@@dataloader') => {
}

function* fetchData(meta: Meta) {
const name = meta.name
const key = meta.dataKey(meta.name, meta.params)

let data: LoaderData = yield select(dataloader.selectors.data)
const id = `${name}/${key}`

const status = data[id]
const status = data[key]
if (data && isDataValid(status, meta)) {
return data
}
Expand Down Expand Up @@ -120,56 +119,34 @@ const plugin = (app: App, namespace: string = '@@dataloader') => {
}
}

const getLoaderStatus = (state: GlobalState, ownProps: DataLoaderProps) => {
const data = dataloader.selectors.data(state)
const name = ownProps.name
// TODO: refactor dataKey to use a string
const key = ownProps.dataKey
? ownProps.dataKey(name, ownProps.params)
: defaultDataKeyFunc(name, ownProps.params)
const dataKey = `${name}/${key}`

return {
loaderStatus: data[dataKey],
}
}

function useDataLoader<TData = any, TParams = any>(
ownProps: DataLoaderProps
) {
const [loaderStatus, setLoaderStatus] = useState<LoaderStatus<TData>>({
const meta: Meta = { ...defaultProps, ...ownProps }
const dispatch = useDispatch()
const data = useSelector(dataloader.selectors.data)
const load = useCallback(
(params?: TParams) => dispatch(effects.load({ ...meta, params })),
[]
)

const key = ownProps.dataKey
? ownProps.dataKey(ownProps.name, ownProps.params)
: defaultDataKeyFunc(ownProps.name, ownProps.params)
const loaderStatus = data[key] || {
data: null,
loading: false,
error: null,
})
const meta: Meta = { ...defaultProps, ...ownProps }
useEffect(() => {
function subscribeToStore() {
const state = app.store.getState()
const { loaderStatus: currentLoaderStatus } = getLoaderStatus(
state,
ownProps
)
if (loaderStatus !== currentLoaderStatus) {
setLoaderStatus(currentLoaderStatus)
}
}
}

const unsubscribe = app.store.subscribe(subscribeToStore)
useEffect(() => {
if (ownProps.autoLoad) {
app.store.dispatch(mutations.init(meta))
dispatch(mutations.init(meta))
} else {
app.store.dispatch(effects.load(meta))
dispatch(effects.load(meta))
}

return unsubscribe
}, [])

const load = (params?: TParams) =>
params
? app.store.dispatch(effects.load({ ...meta, params }))
: app.store.dispatch(effects.load({ ...meta }))

return [loaderStatus, load] as [LoaderStatus<TData>, typeof load]
}

Expand Down
14 changes: 13 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,16 @@ export const isDataValid = (data: LoaderStatus, meta: Meta): boolean => {
return false
}

export const defaultDataKeyFunc = (_: string, __?: any) => `default`
export const defaultDataKeyFunc = (name: string, params?: any) =>
`${name}/${params ? queryString(params) : 'default'}`

export const queryString = (params: any) => {
if (Object.prototype.toString.call(params) === '[object Object]') {
return Object.keys(params)
.map(key => {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key])
})
.join('&')
}
return encodeURIComponent(params)
}
Loading

0 comments on commit 6484b58

Please sign in to comment.