Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A new way to use Redux. We handle reducers and actions for you.

NotificationsYou must be signed in to change notification settings

Yupeng-li/redux-simple-state

Repository files navigation

redux-simple-state automatically generates the redux actions and reducers for you based on the intial state. It lets you add or remove a field in a few seconds and itsget/set API makes the redux development super easy. Instead of spending hours on maintaining actions and reducers, now you can focus on more important works.

Quick start

Create the store and inject the todos state

import{ReduxManager,createState}from"redux-simple-state";// Create storeconststore=ReduxManager.createStore();constINITIAL_STATE={todos:[],visibilityFilter:"SHOW_ALL"};// Generate simple state based on the initial stateconststate=createState("todosState",INITIAL_STATE);//Injects the todos state to the state treeReduxManager.registerState(state);/* *  The state tree now looks like: * { *   todosState:{ *       todos:[], *       visibilityFilter: "SHOW_ALL" *   } * } */

To read the value of visibilityFilter:

letfilter=state.visibilityFilter.get();

To change the value of visibilityFilter:

state.visibilityFilter.set("SHOW_COMPLETED");

To access the selector of visibilityFilter

letvisibilityFilterSelector=state.visibilityFilter.selector;

To insert a new todo to todos

state.todos.addItem({id:0,text:"first todo",completed:false});

To add a new field into the state tree, you can just modify the INITIAL_STATE

constINITIAL_STATE={todos:[],visibilityFilter:"SHOW_ALL",user:null};/* *  The state tree now looks like: * { *   todosState:{ *       todos:[], *       visibilityFilter: "showSHOW_ALL", *       user: null *   } * } */// Get valueletuserDetail=this.state.user.get();// Set valuethis.state.user.set({id:"1"});

You can find the completed example in./examples folder.

  1. todomvc
  2. todomvc-typescript

Introduction

In the most situations, we use Redux as a global state store where we can save our dataglobally and share it among the app. However the cost is that we have to deal with actionsand reducers. Especially for a project with a complex state structure, maintaining theactions, reducers and constants can be very cumbersome.

We just need a place to save data, can we have a simple way to do it?

redux-simple-state is a utility to simplify the process when working with Redux-based projects.The goal of this library is to make the Redux as transparent as possible, so that you can read/writestates without knowing actions and reducers. It doesNOT change the behavior of Redux.Below is a list of highlighted features.

  • Dynamically generates actions and reducers based on the initial state, which allowsyou to add a new filed to the state or change existing state in a few seconds.
  • Every filed in the state tree has a default selector that you can bind to a view or usein a side-effect library such asredux-saga.
  • Has a higher levelget function and aset function to read and write the valueof a field without exposing details of state store and dispatching mechanism.
  • ReduxManager allows you to getState or dispatch an action from anywhere withoutaccessing the Store object directly
  • ReduxManager also allows you to inject new state or reducer on the fly

Note:seamless-immutable isNOT supported yet.

Install

Installredux andreselect first.

yarnaddreduxreselectyarnaddredux-simple-state

Or

npminstall--savereduxreselectnpminstall--saveredux-simple-state
import{applyMiddleware,compose}from"redux";import{ReduxManager}from"redux-simple-state";import{connectRouter}from"connected-react-router";import{routerMiddleware}from"connected-react-router";exportdefaultfunctionconfigureStore(initialState={},history){constenhancers=[applyMiddleware(routerMiddleware(history))];// If Redux DevTools Extension is installed use it, otherwise use Redux composeconstcomposeEnhancers=process.env.NODE_ENV!=="production"&&typeofwindow==="object"&&window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__      ?window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__      :compose;conststore=ReduxManager.createStore(initialState,composeEnhancers(...enhancers));ReduxManager.registerReducer("router",connectRouter(history));// ... rest of your simple states or reducers// ReduxManager.registerState(myState);return{ store};}
import{applyMiddleware,compose}from"redux";import{ReduxManager,createState}from'redux-simple-state'import{persistStore,persistReducer}from"redux-persist";importstoragefrom"redux-persist/lib/storage";import{PersistGate}from"redux-persist/integration/react";...//create storeletpersistor=persistStore(store);constINITIAL_STATE={todos:[],visibilityFilter:"SHOW_ALL"}consttodosState=createState("todos",INITIAL_STATE)constpersistConfig={key:"todos",whitelist:["visibilityFilter","todos"],  storage};// Note: The properties with the prefix underscore are StateContainer's own properties.// The underscroe is used to differentiate from those dynamically added properties.ReduxManager.registerReducer(todosState._name,persistReducer(persistConfig,todosState._reducer));...//wrap your root component with PersistGate

Handle side effects

Withredux-simple-state, you don't have to use any side effects libraries to handle async and complex synchronous logic. Below is an example to show you how to handle side effect withredux-simple-state. Please note thatredux-simple-state is not a middleware of redux, so no extra config is required.

Highlights

  1. You can useasync functions to handle those asynchronous flows. No generator functions, no yields.
  2. No callback hell.
  3. Easy to test
// myState.jsconstINITIAL_STATE={items:[],loading:false,requestError:null};constmyState=createState("myState",INITIAL_STATE);exportdefaultmyState;
// store.jsimport{ReduxManager,createState}from"redux-simple-state";importmyStatefrom"myState.js";conststore=ReduxManager.createStore();ReduxManager.registerState(myState);
//controller.js// Promise versionexportfunctionfetchData(someValue){myState.loading.set(true);returnmyAjaxLib.post("/someEndpoint",{data :someValue}).then(response=>{mystate.items.set(response.data);myState.loading.set(false);myState.requestError.set(null);}).catch(error=>{myState.loading.set(false);myState.requestError.set(error);});}// Async versionexportasyncfunctionfetchDataAsync(someValue){myState.loading.set(true);try{letresponse=awaitmyAjaxLib.post("/someEndpoint",{data :someValue});// let anotherResponse = await myAjaxLib.post("/anotherEndpoint");mystate.items.set(response.data);myState.loading.set(false);myState.requestError.set(null);}catch(error){myState.loading.set(false);myState.requestError.set(error);}}exportfunctionaddTodosIfAllowed(todoText){lettodos=myState.todos.get();if(todos.length<MAX_TODOS){myState.todos.addItem({text :todoText})}}}
// myComponent.jsimportReactfrom'react'import*asmyControllerfrom'controller.js'...exportconstmyComponent=({controller})=>{return<buttononClick={controller.fetchData}>Click to fetch data</button>}myComponent.defaultProps={controller:myController}

If you want to get

API

We generate actions and reducers for a field based on the type of its initial value. These five types are supported.

  1. Object
  2. String
  3. Number
  4. Array
  5. Boolean

If the default value isnull, the field is marked as an Object.

createState

Creates a state. The state is an instance ofStateContainer. You can inject the state to the store when necessary,and use it to get or set value of a field in it.

// THe initial value can be a nested objectletstate=createState("demo",{filter:"all_completed",profile:{id:1,name:"",is_active:true}});ReduxManager.registerState(state);/* *  The state tree now looks like: * { *   demo:{ *       filter: "all_completed", *       profile:{ *            id: 1, *            name: "", *            is_active: true *        } *   } * } */

Params:

  • name (String): The name of the field
  • initialValue (not Function): The default value of the field.

Returns:

AStateContainer instance.

ReduxManager

The singleton instance which allows you to access store from anywhere.

ReduxManager.createStore([preloadedState], [enhancer])

Creates a Redux store that holds the complete state tree of your app.This function is similar as thecreateStorefrom Redux except that it doesn't accept default reducer. Please userReduxManager.register orReduxManger.registerStateto inject the reducers.

Params:

  • preloadedState (string): The initial state.
  • enhancer (Function): The store enhancer.

Returns:

  • Store (Object): Same as the Redux store object.

ReduxManager.registerReducer(name, reducer)

Injects the reducer to the store using the given name. This function is useful when you want to partialy migrate your project to the redux-simple-state, or you have third-party reducer to add in, such as connected-react-route.

Params:

  • name (String): The field name.
  • reducer (Function): A reducing function that returns the next state tree.

Returns:

  • None

Example:

import{ReduxManager}from"redux-simple-state";constinitialState={todos:[],visibilityFilter:"SHOW_ALL"};functiontodoAppReducer(state=initialState,action){switch(action.type){case"SET_VISIBILITY_FILTER":returnObject.assign({},state,{visibilityFilter:action.filter});case"ADD_TODO":returnObject.assign({},state,{todos:[          ...state.todos,{text:action.text,completed:false}]});default:returnstate;}}ReduxManager.registerReducer("todos",todoAppReducer);

ReduxManager.registerState(state)

Injects new state to the store.

Params:

  • state (StateContainer): The state returned bycreateState function. The name of state will be used as the field name.

Returns:

  • None

Example:

import{ReduxManager,createState}from"redux-simple-state";constinitialState={todos:[],visibilityFilter:"SHOW_ALL"};consttodosState=createState("todos",initialState);ReduxManager.registerState(todosState);// To add a todotodosState.todos.addItem({text:"Buy milk",completed:false,id:1});// To change visibilityFiltertodosState.visibilityFilter.set("SHOW_COMPLETED");

ReduxManager.dispatch(action)

Dispatches an action to the store. Same asstore.dispatch in Redux. Please checkRedux document for more details.

Params:

  • action (Object): A plain object describing the change that makes sense for your application.

Returns:

  • (Object): The dispatched action (see notes).

Example:

import{ReduxManager}from"redux-simple-state";letmyAction={type:"SET_VISIBILITY_FILTER",filter:"SHOW_COMPLETED"};ReduxManager.dispatch(myAction);

ReduxManager.getState()

Returns the current state tree of your application. Same asstore.getState in Redux. Please checkRedux document for more details.

Returns:

  • (Any): The current state tree of your application.

Example:

import{ReduxManager}from"redux-simple-state";constcurrentState=ReduxManager.getState();

ReduxManager.select(selector)

Returns the selected value specified by the selector function.

Params:

  • selector (Func): A function that accepts state and returns the selected field value. For example,(state)=>state.user.id;

Returns:

  • (Any): value.

Example:

import{ReduxManager}from"redux-simple-state";letuserFullNameSelector=state=>`${state.user.firstName}${state.user.lastName}`;constuserFullName=ReduxManager.select(userFullNameSelector);

ReduxManager.resetState()

Reset the state tree to its initial value.

Returns:

  • (Action): The reset action.

Example:

import{ReduxManager,createState}from"redux-simple-state";constinitialState={todos:[],visibilityFilter:"SHOW_ALL"};consttodosState=createState("todos",initialState);ReduxManager.registerState(todosState);// To add a todotodosState.todos.addItem({text:"Buy milk",completed:false,id:1});// To change visibilityFiltertodosState.visibilityFilter.set("SHOW_COMPLETED");ReduxManager.resetState();/* The state now is reset to default{  todos:{    todos: [],    visibilityFilter: "SHOW_ALL"  }}*/

StateContainer

A container of a state which gives you all the conveniences to operate the state. You should only create a state container viacreateState function. The function will wire the actions and reducers based on the initial value.

Props:

selector

A selector function which accepts a state object and returns the value of the field

letmyState=createState("demo",{filter:"all_completed",profile:{id:1,name:"",is_active:true}});// For the root fieldletselector=myState.selector;// For sub fieldletfilterSelector=myState.filter.selector;letprofileIdSelector=myState.profile.id.selector;

Use withreact-redux

functionmapStateToProps(state){return{profile:myState.profile.selector(state)};}

Or together withreselect

import{createStructuredSelector}from"reselect";constmapStateToProps=createStructuredSelector({profile:myState.profile.selector});

Use withredux-saga

function*handler(){yieldselect(myState.filter.selector);}

Write your own selectors

import{createSelector}from"reselect";import{SHOW_ALL,SHOW_COMPLETED,SHOW_ACTIVE}from"./constants/TodoFilters";importstatefrom"./todosState";exportconstgetVisibleTodos=createSelector([state.visibilityFilter.selector,state.todos.selector],(visibilityFilter,todos)=>{switch(visibilityFilter){caseSHOW_ALL:returntodos;caseSHOW_COMPLETED:returntodos.filter(t=>t.completed);caseSHOW_ACTIVE:returntodos.filter(t=>!t.completed);default:thrownewError("Unknown filter: "+visibilityFilter);}});exportconstgetTodoCount=createSelector([state.todos.selector],todos=>todos.length);

Functions:

get()

Returns the value of the field. Please make sure you call this function only after the state is registered.

letmyState=createState("demo",{filter:"all_completed",profile:{id:1,name:"",is_active:true},books:[]});//For the root fieldletvalue=myState.get();//For sub fieldletfilter=myState.filter.get();// returns "all_completed"letprofileId=myState.profile.id.get();// returns 1letbooks=mySate.books.get();// return []

set(value)

Set the value of the field. We don't check the type of the new value before writing to the filed. Please make sureto use correct value. For example, the value should be an object if the field is an object.

letmyState=createState("demo",{filter:"all_completed",profile:{id:1,name:"",is_active:true},books:[]});myState.filter.set("show_all");myState.profile.id.set(2);myState.books.set(["Learn JavaScript"]);// for nested objectmyState.profile.set({id:2,name:"test",is_active:false});// If you just want to update the object, you can use `myState.profile.update` instead of set.// There are more details below.

resetToDefault()

Resets the value of the filed to its initial value.

Example:

import{ReduxManager,createState}from"redux-simple-state";constinitialState={todos:[],visibilityFilter:"SHOW_ALL"};consttodosState=createState("todos",initialState);ReduxManager.registerState(todosState);todosState.visibilityFilter.set("SHOW_COMPLETED");todosState.visibilityFilter.get();// return SHOW_COMPLETEDtodosState.visibilityFilter.resetToDefault();todosState.visibilityFilter.get();// return SHOW_ALL

Object Field

Except the shared functions, the Object field has one more function.

update(value)

Update the object. The new value will be merged. Same as doing this:

letnewState={ ...state, ...value};

Params:

  • value(Object)
state.profile.update({is_active:false});

Array Field

Except the shared functions, the Array field has a few more functions to manipulate its items.

addItem(item)

Adds the news item to the end of the array.Params:

  • item(Any)

Example:

...// create todosStatetodosState.todos.addItem({text:"Buy milk",completed:false,id:1})

updateItems(query, value):

Updates all matched items by the given value. If the value is an object, it will be merged to existing object.

Params:

  • query (Function): Query is a function accepts an item in the array, and returns a boolean which indicates if the item is selected.
  • value (Any)

Example:

...// create todosState// Mark todo 1 as completedtodosState.todos.updateItems((todo)=>todo.id===1,{completed:true});// Mark incompleted todos as completedtodosState.todos.updateItems((todo)=>!todo.completed,{completed:true});

updateAll(value)

Updates all the items in the array by the given value. If the value is an object, it will be merged to existing object.

Params:

  • value (Any)

Example:

...// create todosState// Mark all todos as completedtodosState.todos.updateAll({completed:true});

deleteItems(query)

Deletes all matched items.

Params:

  • query (Function): Query is a function accepts an item in the array, and returns a boolean which indicates if the item is selected.

Example:

...// create todosState// Delete all completed todostodosState.todos.deleteItems((todo)=>todo.completed);

deleteAll()

Deletes all items.

Example:

...// create todosState// Delete all todostodosState.todos.deleteAll();

About

A new way to use Redux. We handle reducers and actions for you.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors2

  •  
  •  

[8]ページ先頭

©2009-2025 Movatter.jp