react-natural-store 使用手册
此包已经迁移到natur
- 如果您的项目想从react-natural-store迁移到natur,那么可以看此迁移导航,主要是maps必须要手动声明依赖,其他的还好
- natur是较为稳定,推荐的版本。她的兼容性,便捷性,性能都相对优异
设计概念
基本介绍
- 这是一个简洁、高效的react状态管理器
- 浏览器兼容:IE9+
- 支持react 15.x, 16.x, 以及anujs
- 单元测试覆盖率99%,放心使用
- 包体积,minizip 5k(uglify+gzip压缩后5k)
第一步 创建 store 实例
这一步需要在渲染组件之前完成,因为 inject方法包裹的组件,在渲染时依赖store的实例
; /*此处app视为一个模块一个模块的数据结构就是如此*/const app = // state 必须是Object对象,子元素不限 state: name: 'tom' todos: text: 'play game ' games: 'favorite' 'lol' // actions必须是Object对象,子元素必须是function actions: /* 返回的参数 如果是Object则会作为新的state, 如果不是则不会处理,并原值返回给调用者。 需要遵照immutable规范!!! */ name: newName /* 支持promise, 返回值行为与上面的同步action一致 */ Promise // /* 可选的参数,必须是Object对象,子元素必须是Function 或者 Array<String | Function> 在页面获取的maps,会是运行后的函数返回值, maps方法会自动收集依赖,只有在依赖发生变化时,才会重新计算结果。 */ maps: // 如果map仅仅是使用state第一层数据,可以直接写一个函数 statename statename + lastName /** * 如果你的map对性能有要求, * 并且依赖state的深层数据、或复杂数据,可以手动依赖声明 * 这个示例只有在 todos[0].text 或者 s.info.get('favorite')数据发生变化时,才会重新计算结果 */ deepDep: /* 对于常见数据类型,你可以使用字符串路径声明依赖 如果获取的时候发生错误,则会自动返回undefined */ 'todos[0].text' sinfo // 对于复杂类型,你可以使用函数声明依赖 firstTodo + favorite; // 'play game lol' ; // 其他的模块const otherModules = //... ; // 创建store实例const store = ; ;
第二步 使用 inject 将模块注入组件当中
import inject from 'react-natural-store';const App = app otherModuleName // 获取注入的app模块 const state actions maps = app; /* 获取到的 app模块 state: { name: 'tom' }, actions: { changeName, asyncChangeName, }, maps: { splitName: ['t', 'o', 'm'], addName: lastName => state.name + lastName, } */ return <input = // 中的数据 = /> ; // 注入store中的app模块;'app' 'otherModuleName'App;
好了,你已经掌握了。以下是一些附加功能。
- hooks方式
- 配置懒加载模块
- 初始化store时,使用其他的state
- 中间件
- 懒加载模块,加载中,占位组件配置
- 在react外使用store
- 手动导入模块
- 在typescript中使用
- 其他版本
- 使用注意事项
第二步可以换成hooks使用方式 使用 useInject 将 app 模块注入组件当中
import useInject from 'react-natural-store'; const App = /* 注意,如果useInject参数中,存在懒加载模块,则会先返回空的数组, 等到懒加载模块加载完成才会返回你需要的模块, 所以useInject不建议使用于懒加载模块 但是你可以使用手动添加模块的的方式 store.setModule('otherModuleName', otherModule); 详情见手动导入模块说明 */ const app otherModule = ; const state actions maps = app; return <input = = /> ;;
懒加载模块配置
/* module1.js export { state: { count: 1, } actions: { inc: state => ({count: state.count + 1}), } } */const otherLazyModules = // module2: () => import('module2'); // ...const module1 = import'module1'; // 懒加载模块 // 第二参数就是懒加载的模块;const store = ; // 创建store实例 // 然后用法等同于第二步
createStore初始化state
import createStore from 'react-natural-store';const app = state: name: 'tom' actions: name: newName Promise ;/* createStore第三个参数 { [moduleName: ModuleName]: Partial<State>, }*/const store = ; ;
中间件
import createStore MiddleWare Next Record from 'react-natural-store';const app = state: name: 'tom' actions: name: newName Promise ;/* 抄的redux middleware, type Record = { moduleName: String, actionName: String, state: ReturnType<Action>,} type Next = (record: Record) => ReturnType<Action>; middlewareParams: { setState: Next, getState: () => State,}; */const LogMiddleware: MiddleWare = middlewareParams next: Next record: Record console; return ; // 你应该return, 只有这样你在页面调用action的时候才会有返回值 // return middlewareParams.setState(record); // 你应该return,只有这样你在页面调用action的时候才会有返回值;const store = ; ;
加载时候的占位组件配置
import inject from 'react-natural-store';// 全局配置inject; // 局部使用App <div>loading</div>;
在react之外使用store
// 引入之前创建的store实例; /* 获取注册的app模块, 等同于在react组件中获取的app模块 如果你想要获取懒加载的模块, 那么你必须确定,这个时候该模块已经加载好了*/const app = store;/* 如果你确定,懒加载模块,还没有加载好 你可以监听懒加载模块,然后获取*/store; /*state: { name: 'tom'},actions: { changeName, asyncChangeName,},maps: { splitName: ['t', 'o', 'm'], addName: lastName => state.name + lastName,}*/ /* 当你在这里使用action方法更新state时, 所有注入过app模块的组件都会更新, 并获取到最新的app模块中的数据, 建议不要滥用*/appactions; // 监听模块变动const unsubscribe = store; // 取消监听;
手动导入模块
// initStore.ts; // 在实例化store的时候,没有导入懒加载模块; // ================================================// lazyloadPage.ts 这是一个懒加载的页面; ;/*手动添加模块,在此模块被添加之前,其他地方无法使用此模块要想其他地方也使用,则必须在store实例化的时候就导入*/store.setModule'lazyModuleName', lazyLoadModule;
typescript支持
;; ; ; ;ReactDOM.render app, document.querySelector'#app';
使用注意事项
-
由于低版本不支持react.forwardRef方法,所以不能直接使用ref获取包裹的组件实例,需要使用forwardedRef属性获取(用法同ref)
-
在TypeScript中的提示可能不那么友好,比如
// 此使用方法会报错,提示App组件中无forwardedRef属性声明App forwardedRef= / // 以下使用方式则不会报错;// 正确App forwardedRef= /
-
在actions中修改state,需要遵循immutable规范。maps只监听state下第一层值的变化,所以如果第一层值没有变化,但是state深层值确实有变化,那么对应的maps缓存不会刷新。
-
请尽量避免在actions中动态增加或删除state的key。这会导致一个问题,当maps依赖state动态增加或删除的key时,由于Object.defineProperty无法监听到增加key或删除key的变化,所以对应的maps不会重新计算,依然会使用上次的缓存。