Redux-based framework to get rid of CRUD-related boilerplate
inspired by DCK (Dashboard Construction Kit)
- TypeScript 3.7 (with optional chaining & nullish coalescing)
redux
redux-toolkit
react-redux hooks
immer
redux-saga
- Testing tools
jest
redux-saga-tester
@testing-library/react
- Zero-config CLI for TypeScript package development
tsdx
- CI github actions
import React from 'react'
import {
useItems,
useOptedItem,
useLoading,
useLoadItems,
useSetItems,
} from '@ambroseus/dck-store'
export const Items: React.FC<{ itemType: string; optedItemId?: number }> = ({
itemType,
optedItemId,
}) => {
const items: any[] = useItems(itemType)
const loading = useLoading(itemType)
const load = useLoadItems(itemType)
const setItems = useSetItems(itemType)
const optedItem = useOptedItem(itemType)
return (
<>
<button onClick={() => load({ optedItemId })} disabled={loading}>
{loading ? 'loading...' : 'load items'}
</button>{' '}
<button onClick={() => setItems([])}>clear items</button>
<div />
<pre>items: {JSON.stringify(items, null, 2)}</pre>
<pre>opted item: {JSON.stringify(optedItem, null, 2)}</pre>
</>
)
}
...
import React from 'react'
import { Provider } from 'react-redux'
import { store } from './store'
import { Items } from './components/Items'
import { TestItem } from './items'
export const App: React.FC = () => (
<Provider store={store}>
<Items itemType={TestItem} optedItemId={3} />
</Provider>
)
import { all, takeLatest } from 'redux-saga/effects'
import { Process, isAction } from '@ambroseus/dck-store'
import { testLoadFetcher } from './fetchers'
import { TestItem } from './items'
export function* rootSaga() {
yield all([takeLatest(isAction.Load(TestItem), loadTestItemsSaga)])
}
function* loadTestItemsSaga(action: any) {
const proc = new Process.Load(TestItem)
yield proc.start()
try {
yield proc.fetch()
yield proc.setItems(proc.data)
yield proc.optItem(action.meta.options.optedItemId)
yield proc.stop()
} catch (e) {
yield proc.fail(e)
}
}
import { configureStore } from '@reduxjs/toolkit'
import createSagaMiddleware from 'redux-saga'
import { dckReducer } from '@ambroseus/dck-store'
import { rootSaga } from './rootSaga'
const sagaMiddleware = createSagaMiddleware()
export const store = configureStore({
reducer: { dck: dckReducer },
middleware: [sagaMiddleware],
preloadedState: {},
})
sagaMiddleware.run(rootSaga)