0.3.87 • Published 3 years ago

saga-resource v0.3.87

Weekly downloads
200
License
MIT
Repository
github
Last release
3 years ago

npm Build Status codecov

saga-resource

Write your store in one place, without boilerplates

Features:

  • Easy to implement on your current redux + redux-saga architecture

The initial setup

Make your resource

// ./store/counter.ts
import {delay, put} from 'redux-saga/effects';
import {makeResource} from 'saga-resource';

interface CounterState {
    count: number;
}

interface CounterReducers {
    inc: (num?:number) => CounterState;
}

interface CounterEffects {
    asyncInc: (num?:number) => any;
}

const counter = makeResource<CounterState, CounterReducers, CounterEffects>({
    name: 'counter',
    state: {
        count: 0,
    },
    reducers: {
        inc: (num=1, {state}) => {
            return {...state, ...{count: state.count + num}};
        },
    },
    effects: {
        *asyncInc(num=1): any {
            yield delay(500);
            yield put(counter.actions.inc(num));
        },
    },
});

export default counter;

Make your store

// ./store/index.ts
import {combineResources} from 'saga-resource'
import counter from './counter'

const combinedResources = combineResources({counter})

const rootReducer = combinedResources.combineReducers()
const rootSaga = combinedResources.getSaga()

export type AppState = ReturnType<typeof rootReducer>

const sagaMiddleware = createSagaMiddleware();

const store = createStore(rootReducer, bindMiddleware(sagaMiddleware))
sagaMiddleware.run(rootSaga)

export default store

You are all setup, let's dispatch resource actions from your component.

// ./YourComponent.jsx
import counter from 'store/counter';

// ...
const mapDispatchToProps = (dispatch) => {
    return {
        add5: dispatch(counter.actions.inc(5))
        asyncAdd: dispatch(counter.actions.asyncInc())
    }
}
// ...

actions will be generated by reducers and effects you defined.

yield saga-resource effect from your saga file.

// ./YourSagaFile.js
import counter from 'store/counter';
// ...
function* asyncAdd5(){
    try {
        yield counter.effects.asyncInc(5)
    }
}
// ...

Built-in reducers

There are 3 built in reducers, set, update, clear set will overwrite your state e.g. dispatch(resource.actions.set(newState)) update will set the key with the payload, the key can be a path, e.g. update your key 'a.b.c with data' dispatch(resource.actions.update('a.b.c', data)) clear clear will reset your state to it's initial state. e.g. dispatch(resource.actions.clear())

Built-in effects

There are 4 built-in effects, createRequest, updateRequest, fetchRequest, deleteRequest, these four effects will send request corresponds to post, patch, get, delete, with an exception that fetchRequest will set your state based on data the request returns.

You can call these methods only if you have a path setup in your resource definition.

For example:

// ./store/user.ts
import {makeResource} from 'saga-resource';

export interface UserState {
    username: string;
}

const user = makeResource<UserState, {}, {}>({
    name: 'user',
    path: 'http://localhost:8080/user',
    state: {
        username: 'Uninitialized user',
    },
});

export default user;

Fetch user by dispatch(user.actions.fetchRequest()) Or you can use effect directly in you saga file yield user.effects.fetchRequest()

Loading status

All effects will have loading status stored in resourceState.meta.loading

Error handling

When ever resource effects throws an error, { type: SagaResource.actionTypes.ERROR, data } will be dispatched.

0.3.87

3 years ago

0.3.86

3 years ago

0.3.85

3 years ago

0.3.84

4 years ago

0.3.83

4 years ago

0.3.82

5 years ago

0.3.81

5 years ago

0.3.8

5 years ago

0.3.7

5 years ago

0.3.6

5 years ago

0.3.5

5 years ago

0.3.4

5 years ago

0.3.3

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.0

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago

0.0.1

5 years ago