Gathering detailed insights and metrics for redux-methods
Gathering detailed insights and metrics for redux-methods
Gathering detailed insights and metrics for redux-methods
Gathering detailed insights and metrics for redux-methods
@redux-saga/deferred
Helper for creating "exposed" promise object (with resolve & reject methods).
react-redux-methods
A lightweight react-redux toolkit for writing strong-typed, minimal code redux boilerplate.
fusion-plugin-rpc-redux-react
Triggers Redux actions when RPC methods are called.
fusion-rpc-redux
Triggers Redux actions when RPC methods are called
npm install redux-methods
Typescript
Module System
Node Version
NPM Version
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
27
No more boilerplate for common actions. Define your initial state and common actions once, then access the actions anywhere in one object.
1npm install redux-methods
OR
1yarn add redux-methods
1// initialState.js 2 3const initialState = { 4 ui: { 5 isOnline: true, 6 isSidebarOpen: true, 7 errorMessage: '', 8 }, 9 inProgress: { 10 isGettingProfile: false, 11 }, 12 user: { 13 profile: {} 14 } 15 16 export default initialState;
OR
1// ui.js 2 3export const ui = { 4 isOnline: true, 5 isSidebarOpen: true, 6 errorMessage: '', 7}; 8 9//... similar for inProgress.js, user.js
1//initialState.js 2 3export { ui } from './ui'; 4export { inProgress } from './inProgress'; 5export { user } from './user';
1// in store.js 2 3import * as initialState from './initialState'; 4 5//... etc
Methods should be defined in camel case, and not conflict with any properties in your initial state. These methods will be your action types which can be dispatched on any property in your initial state.
1// methods.js 2 3/** 4 * @description - each action method is called with the below, and must return 5 * the new value for the slice 6 * @param {*} payload - The payload provided to the action method creator 7 * @param {*} slice - reference to the slice of state provided by the path of the action 8 * method creator. Mutation should be avoided. 9 * @param {*} initial - reference to the slice of initial state provided by the path of the 10 * action method creator. Mutation should be avoided. 11 */ 12 13export const setValue = payload => payload; 14export const increment = (payload, slice) => slice + payload; 15export const decrement = (payload, slice) => slice - payload; 16export const addById = (payload, slice) => ({ ...slice, [payload.id]: payload }); 17export const reset = (payload, slice, initial) => initial;
You can define additional methods such as thunks, selectors, or other simple actions that you don't want shared with all properties as an object of functions. These will all be accessible in the methods object at their respective path. Each object of additional methods will be merged in to the methods object.
1// thunks.js 2 3export const fetchProfile = payload => dispatch => dispatch(someAction(payload)); 4//async action here 5 6// selectors.js 7 8export const selectProfile = state => state.user.profile; //selector here
Pass in your defined methods, and any additional objects containing functions you want to have access to in the methods object.
1// store.js 2 3import { createStore } from 'redux'; 4import initialState from './initialState'; // or import * as initialState 5import { methodsEnhancer } from 'redux-methods'; 6import * as methods from './methods'; 7import * as thunks from './thunks'; 8import * as selectors from './selectors'; 9 10/** 11 * @description - methodsEnhancer initialises redux-methods 12 * @param {{}} methods - The methods you have defined which will become your 13 * action types available at every property defined in your initialState. 14 * @param {{}} ...additionalMethods - additional arguments should be objects 15 * containing additional methods, eg thunks, selectors, or other action creators. 16 */ 17 18const store = createStore(reducer, initialState, methodsEnhancer(methods, thunks, selectors)); 19 20export default store;
If you are using namespaced reducers (for example, using combineReducers) the initialState created by redux-methods will cause an error (unexpected keys) - to work around this, spread the createPassthroughReducers function with the initialState as its argument to create a reducer for each namespace in your defined initialState that simply returns the state.
1// reducer.js 2 3import { combineReducers } from 'redux'; 4import { createPassthroughReducers } from 'redux-methods'; 5import initialState from './initialState'; 6 7const reducer = combineReducers({ 8 ...createPassthroughReducers(initialState), 9 someReducer: state => state, 10}); 11 12export default reducer;
1// someContainer.js 2 3import { connect } from 'react-redux'; 4import methods from 'redux-methods'; 5import someComponent from './someComponent'; 6 7const mapStateToProps = state => ({ 8 profile: methods.selectProfile(state), 9}); 10 11const mapDispatchToProps = { 12 fetchProfile: methods.fetchProfile, 13}; 14 15export default connect( 16 mapStateToProps, 17 mapDispatchToProps, 18)(someComponent); 19 20// thunks.js 21 22import methods from 'redux-methods'; 23 24export const fetchProfile = payload => dispatch => { 25 const { 26 inProgress: { isGettingProfile }, 27 ui: { errorMessage }, 28 user: { profile }, 29 } = methods; 30 31 dispatch(isGettingProfile.set(true)); 32 33 return axios 34 .get(`api.domain.com/profile/${payload}`) 35 .then(res => { 36 dispatch(profile.set(res.data)); 37 dispatch(isGettingProfile.set(false)); 38 }) 39 .catch(e => dispatch(errorMessage(e.message))); 40};
Two methods are provided at the root level of the methods object - tutti and custom. See below for the previous example rewritten using these methods.
methods.tutti
- this method allows you to perform multiple actions in a single dispatch.
By using this method you will need to look at the action itself in Redux Dev Tools to see which actions were performed.
methods.custom
- this method allows you to perform any of your defined method actions on a path that you were unable to define in your initialState. It will create the path if it doesn't exist.
1// someContainer.js 2 3import { connect } from 'react-redux'; 4import methods from 'redux-methods'; 5import someComponent from './someComponent'; 6 7const mapStateToProps = state => ({ 8 profile: methods.selectProfile(state), 9}); 10 11const mapDispatchToProps = { 12 fetchProfile: methods.fetchProfile, 13 updateName: methods.custom.set('user.profile.name', 'Bob'), 14}; 15 16export default connect( 17 mapStateToProps, 18 mapDispatchToProps, 19)(someComponent); 20 21// thunks.js 22 23import methods from 'redux-methods'; 24 25export const fetchProfile = payload => dispatch => { 26 const { 27 inProgress: { isGettingProfile }, 28 tutti, 29 ui: { errorMessage }, 30 user: { profile }, 31 } = methods; 32 33 dispatch(isGettingProfile.set(true)); 34 35 return axios 36 .get(`api.domain.com/profile/${payload}`) 37 .then(res => { 38 dispatch(tutti(profile.set(res.data), isGettingProfile.set(false))); 39 }) 40 .catch(e => dispatch(errorMessage(e.message))); 41};
The methodsEnhancer function does two things.
Firstly, it creates an object with the same deep properties as the provided initialState, excluding final values. Each property contains an action creator for each of the provided methods.
Example
1const initialState = { 2 ui: { 3 inProgress: { 4 isGettingProfile: false, 5 }, 6 isOnline: true, 7 }, 8}; 9const methods = { 10 increment: (payload, slice) => slice + payload, 11 reset: (payload, slice, initial) => initial, 12 setValue: payload => payload, 13}; 14 15// using the above initialState and methods passed to methodsEnhancer, the 16// imported methods object would be as below: 17 18methods = { 19 custom: { 20 increment: (path, payload) => ({ 21 path, 22 payload, 23 type: '@@redux-methods/INCREMENT', 24 }), 25 reset: (path, payload) => ({ 26 path, 27 payload, 28 type: '@@redux-methods/RESET', 29 }), 30 setValue: (path, payload) => ({ 31 path, 32 payload, 33 type: '@@redux-methods/SET_VALUE', 34 }), 35 }, 36 tutti: payload => ({ 37 payload, 38 type: '@@redux-methods/TUTTI', 39 }), 40 ui: { 41 increment: payload => ({ 42 path: 'ui', 43 payload, 44 type: '@@redux-methods/INCREMENT', 45 }), 46 reset: payload => ({ 47 path: 'ui', 48 payload, 49 type: '@@redux-methods/RESET', 50 }), 51 setValue: payload => ({ 52 path: 'ui', 53 payload, 54 type: '@@redux-methods/SET_VALUE', 55 }), 56 inProgress: { 57 increment: payload => ({ 58 path: 'ui.inProgress', 59 payload, 60 type: '@@redux-methods/INCREMENT', 61 }), 62 reset: payload => ({ 63 path: 'ui.inProgress', 64 payload, 65 type: '@@redux-methods/RESET', 66 }), 67 setValue: payload => ({ 68 path: 'ui.inProgress', 69 payload, 70 type: '@@redux-methods/SET_VALUE', 71 }), 72 isGettingProfile: { 73 increment: payload => ({ 74 path: 'ui.inProgress.isGettingProfile', 75 payload, 76 type: '@@redux-methods/INCREMENT', 77 }), 78 reset: payload => ({ 79 path: 'ui.inProgress.isGettingProfile', 80 payload, 81 type: '@@redux-methods/RESET', 82 }), 83 setValue: payload => ({ 84 path: 'ui.inProgress.isGettingProfile', 85 payload, 86 type: '@@redux-methods/SET_VALUE', 87 }), 88 }, 89 }, 90 isOnline: { 91 increment: payload => ({ 92 path: 'ui.isOnline', 93 payload, 94 type: '@@redux-methods/INCREMENT', 95 }), 96 reset: payload => ({ 97 path: 'ui.isOnline', 98 payload, 99 type: '@@redux-methods/RESET', 100 }), 101 setValue: payload => ({ 102 path: 'ui.isOnline', 103 payload, 104 type: '@@redux-methods/SET_VALUE', 105 }), 106 }, 107 }, 108};
Secondly, it creates a root-level reducer. This reducer checks if the action type is a defined method. If it isn't, it passes the action on to the default reducer.
Otherwise, it reduces down to the slice of state (and initial state) determined by the path value, then passes those slices and payload to the defined method which matches the action type.
No vulnerabilities found.
No security vulnerabilities found.