@cimacmillan/refunc
TypeScript icon, indicating that this package has built-in type declarations

1.0.3 • Public • Published

Refunc

Redux-like state container with actions as functions

By Callum Macmillan

Quick start

Installing

npm install @cimacmillan/refunc

Usage

Refunc takes actions as functions, with payload as parameters

const emptyActions = {
    increment: () => {},
    addX: (x: number) => {}
}

Reducers are defined as their initial state and functions for transforming state based on actions

const reducer = {
    state: {
        count: 0
    },
    actions: {
        increment: (state: State) => ({...state, count: state.count + 1}),
        addX: (state: State, x: number) => ({...state, count: state.count + x}),
    }
}

The store is created by passing a reducer definition, and the empty actions

const store = new Store(
    reducer,
    emptyActions
);

The store is updated by calling actions

store.getActions().increment();
store.getActions().addX(10);
// store.getState() = { count: 11 }

The store can notify listeners of changes to the state

store.addChangeListener(() => {
    console.log(`new state is ${store.getState()}`)
});

The stores actions can be subscribed to

store.subscribe({
    increment: () => {
        console.log("increment was called");
    },
    addX: (x: number) => {
        console.log(`addX was called with ${x}`);
    }
})

Multiple reducers can be combined with combineReducers

const countReducer: Reducer<CountState, Actions> = {
    state: 0,
    actions: {
        increment: (state: CountState) => (state + 1),
        addX: (state: CountState, x: number) => (state + x),
    }
}

const numberOfCallsReducer: Reducer<CallRecordState, Actions> = {
    state: 0,
    actions: {
        increment: (state: CountState) => (state + 1),
        addX: (state: CountState, x: number) => (state + 1),
    }
}

const store = new Store(
    combineReducers({
        count: countReducer,
        numberOfCalls: numberOfCallsReducer
    }),
    emptyActions
);

// store.getState() = { count: 0, numberOfCalls: 0 }

store.getActions().increment();

// store.getState() = { count: 1, numberOfCalls: 1 }

store.getActions().addX(10);

// store.getState() = { count: 11, numberOfCalls: 2 }

This can be used with React hooks with these effects

export const useGlobalState: () => [State, Actions] = () => {
    const [storeState, setStore] = React.useState(store.getState());
    React.useEffect(() => {
        const callback = () => setStore(store.getState());
        store.addChangeListener(callback);
        return () => store.removeChangeListener(callback);
    }, []);
    return [storeState, store.getActions()];
};

export const useDispatchListener = (actions: Partial<Actions>, deps: any[]) => {
    React.useEffect(() => {
        store.subscribe(actions);
        return () => store.unsubscribe(actions);
    }, deps);
}

Readme

Keywords

none

Package Sidebar

Install

npm i @cimacmillan/refunc

Weekly Downloads

1

Version

1.0.3

License

GPL-3.0-or-later

Unpacked Size

63.8 kB

Total Files

23

Last publish

Collaborators

  • cimacmillan