├── .eslintignore ├── .gitignore ├── .browserslistrc ├── .travis.yml ├── tests ├── fixtures │ ├── types.js │ ├── container.js │ ├── actions.js │ └── reducer.js ├── helper.js ├── types.js ├── reset.js ├── container.jsx ├── reducer.js └── actions.js ├── .eslintrc ├── appveyor.yml ├── gulpfile.js ├── .babelrc ├── .editorconfig ├── .nycrc ├── docs ├── types.md ├── install.md ├── container.md ├── use.md ├── actions.md ├── reducer.md └── options.md ├── package.json ├── README.md └── src └── index.js /.eslintignore: -------------------------------------------------------------------------------- 1 | lib 2 | coverage 3 | node_modules 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | lib 3 | !lib/.gitkeep 4 | node_modules 5 | coverage 6 | .nyc_output 7 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # Browsers that we support 2 | 3 | > 1% 4 | Last 2 versions 5 | IE 10 # sorry 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "9" 5 | - "10" 6 | script: 7 | - npm test 8 | - npm run report 9 | -------------------------------------------------------------------------------- /tests/fixtures/types.js: -------------------------------------------------------------------------------- 1 | export const POST_TITLE = '@@post/TITLE'; 2 | export const POST_BODY = '@@post/BODY'; 3 | export const POST_SUBMIT = '@@post/SUBMIT'; 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "mocha": true 8 | }, 9 | "rules": { 10 | "react/destructuring-assignment": 0 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: "8" 4 | install: 5 | - ps: Install-Product node $env:nodejs_version 6 | - npm install 7 | test_script: 8 | - node --version 9 | - npm --version 10 | - npm test 11 | build: off 12 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const babel = require('gulp-babel'); 3 | const cleanDest = require('gulp-clean-dest'); 4 | 5 | gulp.task('default', () => gulp.src(['./src/index.js']) 6 | .pipe(cleanDest('lib')) 7 | .pipe(babel()) 8 | .pipe(gulp.dest('lib'))); 9 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-class-properties", 8 | "@babel/plugin-proposal-object-rest-spread", 9 | "@babel/plugin-syntax-dynamic-import" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tests/fixtures/container.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import * as actions from './actions'; 3 | 4 | export const POST = '@@post/POST'; 5 | 6 | const mapStateToProps = state => state[POST]; 7 | const mapDispatchToProps = { ...actions }; 8 | 9 | export default connect(mapStateToProps, mapDispatchToProps); 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Set default charse 12 | charset = utf-8 13 | 14 | # 2 space indentation 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /tests/fixtures/actions.js: -------------------------------------------------------------------------------- 1 | import { 2 | POST_TITLE, 3 | POST_BODY, 4 | POST_SUBMIT, 5 | } from './types'; 6 | 7 | export const titleAction = title => ({ 8 | type: POST_TITLE, 9 | title, 10 | }); 11 | 12 | export const bodyAction = body => ({ 13 | type: POST_BODY, 14 | body, 15 | }); 16 | 17 | export const submitAction = () => ({ 18 | type: POST_SUBMIT, 19 | }); 20 | -------------------------------------------------------------------------------- /tests/fixtures/reducer.js: -------------------------------------------------------------------------------- 1 | import { POST_TITLE, POST_BODY } from './types'; 2 | 3 | export const defaultState = { 4 | title: '', 5 | body: '', 6 | }; 7 | 8 | export default (state = defaultState, action) => { 9 | switch (action.type) { 10 | case POST_TITLE: 11 | case POST_BODY: 12 | return { ...state, ...action }; 13 | default: 14 | return state; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "extension": [".js",".jsx"], 3 | "require": ["./tests/helper.js"], 4 | "exclude": [ 5 | "node_modules", 6 | "lib", 7 | "coverage", 8 | "tests", 9 | "gulpfile.js" 10 | ], 11 | "check-coverage": true, 12 | "per-file": false, 13 | "statements": 100, 14 | "branches": 98, 15 | "functions": 100, 16 | "lines": 100, 17 | "reporter": [ 18 | "lcov", 19 | "text", 20 | "text-summary", 21 | "html" 22 | ], 23 | "all": true 24 | } 25 | -------------------------------------------------------------------------------- /tests/helper.js: -------------------------------------------------------------------------------- 1 | require('@babel/register'); 2 | 3 | const { configure } = require('enzyme'); 4 | const Adapter = require('enzyme-adapter-react-16'); 5 | 6 | configure({ adapter: new Adapter() }); 7 | 8 | const { JSDOM } = require('jsdom'); 9 | 10 | const exposedProperties = ['window', 'navigator', 'document']; 11 | 12 | const { window } = new JSDOM('', { url: 'http://localhost' }); 13 | global.document = window.document; 14 | global.window = window; 15 | Object.keys(document.defaultView).forEach((property) => { 16 | if (typeof global[property] === 'undefined') { 17 | exposedProperties.push(property); 18 | global[property] = document.defaultView[property]; 19 | } 20 | }); 21 | 22 | global.navigator = { 23 | userAgent: 'node.js', 24 | }; 25 | 26 | global.localStorage = { 27 | setItem() {}, 28 | }; 29 | 30 | global.documentRef = document; 31 | -------------------------------------------------------------------------------- /tests/types.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import RL from '../src'; 3 | import * as types from './fixtures/types'; 4 | 5 | const rl = new RL('post'); 6 | 7 | rl.addAction('title', { title: '' }); 8 | rl.addAction('body', { body: '' }); 9 | rl.addAction('submit'); 10 | 11 | const { types: rlTypes } = rl.flush(); 12 | 13 | describe('Testing types', () => { 14 | describe('Redux', () => { 15 | it('should test POST_TITLE', () => { 16 | expect(types.POST_TITLE).to.be.equal('@@post/TITLE'); 17 | }); 18 | 19 | it('should test POST_BODY', () => { 20 | expect(types.POST_BODY).to.be.equal('@@post/BODY'); 21 | }); 22 | 23 | it('should test POST_SUBMIT', () => { 24 | expect(types.POST_SUBMIT).to.be.equal('@@post/SUBMIT'); 25 | }); 26 | }); 27 | 28 | describe('Redux Lazy', () => { 29 | it('should test POST_TITLE', () => { 30 | expect(rlTypes.POST_TITLE).to.be.equal('@@post/TITLE'); 31 | }); 32 | 33 | it('should test POST_BODY', () => { 34 | expect(rlTypes.POST_BODY).to.be.equal('@@post/BODY'); 35 | }); 36 | 37 | it('should test POST_SUBMIT', () => { 38 | expect(rlTypes.POST_SUBMIT).to.be.equal('@@post/SUBMIT'); 39 | }); 40 | 41 | it('should test type with camelCase to underscore', () => { 42 | const newRl = new RL('newPost'); 43 | newRl.addAction('newTitle', { title: '' }); 44 | const { types: newRlTypes } = newRl.flush(); 45 | 46 | expect(newRlTypes.NEW_POST_NEW_TITLE).to.be.equal('@@newPost/NEW_TITLE'); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /docs/types.md: -------------------------------------------------------------------------------- 1 | # Types 2 | 3 | ## If you use redux you need to create [types](https://redux.js.org/basics/actions): 4 | 5 | ```javascript 6 | export const POST_TITLE = '@@post/TITLE'; 7 | export const POST_BODY = '@@post/BODY'; 8 | export const POST_SUBMIT = '@@post/SUBMIT'; 9 | ``` 10 | 11 | ## Redux Lazy 12 | 13 | With Redux Lazy you don't need to make it manually. 14 | Create **rl.js** file inside of your module and put code like this: 15 | 16 | ```javascript 17 | import RL from 'redux-lazy'; 18 | 19 | const rl = new RL('post'); 20 | 21 | rl.addAction('title', { title: '' }); 22 | rl.addAction('body', { body: '' }); 23 | rl.addAction('submit'); 24 | 25 | export default rl; 26 | ``` 27 | How to add actions see [docs](https://github.com/evheniy/redux-lazy/blob/master/docs/actions.md). 28 | 29 | Then import **rl** where you need it: 30 | 31 | ```javascript 32 | import rl from './rl'; 33 | 34 | const { types } = rl; 35 | ``` 36 | 37 | ## Testing 38 | 39 | ```javascript 40 | import { expect } from 'chai'; 41 | import rl from '../src/rl'; 42 | 43 | const { types } = rl.flush(); 44 | 45 | describe('Testing types', () => { 46 | it('should test POST_TITLE', () => { 47 | expect(types.POST_TITLE).to.be.equal('@@post/TITLE'); 48 | }); 49 | 50 | it('should test POST_BODY', () => { 51 | expect(types.POST_BODY).to.be.equal('@@post/BODY'); 52 | }); 53 | 54 | it('should test POST_SUBMIT', () => { 55 | expect(types.POST_SUBMIT).to.be.equal('@@post/SUBMIT'); 56 | }); 57 | }); 58 | 59 | ``` 60 | 61 | ## Documentation 62 | 63 | * [Install](https://github.com/evheniy/redux-lazy/blob/master/docs/install.md) 64 | * [How to use](https://github.com/evheniy/redux-lazy/blob/master/docs/use.md) 65 | * [Actions](https://github.com/evheniy/redux-lazy/blob/master/docs/actions.md) 66 | * [Reducer](https://github.com/evheniy/redux-lazy/blob/master/docs/reducer.md) 67 | * [Container](https://github.com/evheniy/redux-lazy/blob/master/docs/container.md) 68 | * [Options](https://github.com/evheniy/redux-lazy/blob/master/docs/options.md) 69 | 70 | 71 | [More examples](https://github.com/evheniy/redux-lazy/blob/master/tests/types.js) 72 | -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | # Install 2 | 3 | ## How to install 4 | 5 | npm i -S redux-lazy 6 | 7 | Or 8 | 9 | yarn add redux-lazy 10 | 11 | ## How to use 12 | 13 | To work with Redux Lazy you need to make only 3 steps: 14 | 15 | ### 1. Import redux-lazy 16 | 17 | ```javascript 18 | import RL from 'redux-lazy'; 19 | ``` 20 | 21 | ### 2. Create a instance 22 | 23 | ```javascript 24 | const rl = new RL('post'); 25 | ``` 26 | 27 | ### 3. Add actions 28 | 29 | ```javascript 30 | rl.addAction('title', { title: '' }); 31 | rl.addAction('body', { body: '' }); 32 | ``` 33 | After that you can flush all code for working with redux: 34 | 35 | ```javascript 36 | const { 37 | nameSpace, 38 | types, 39 | actions, 40 | defaultState, 41 | reducer, 42 | mapStateToProps, 43 | mapDispatchToProps, 44 | Container, 45 | } = rl.flush(); 46 | ``` 47 | 48 | You can export each type and action: 49 | 50 | ```javascript 51 | const { 52 | nameSpace, 53 | types, 54 | actions, 55 | ... 56 | } = rl.flush(); 57 | 58 | const { titleAction, bodyAction } = actions; 59 | const { POST_TITLE, POST_BODY } = types; 60 | 61 | export default rl; 62 | 63 | export { 64 | nameSpace, 65 | titleAction, 66 | bodyAction, 67 | POST_TITLE, 68 | POST_BODY, 69 | }; 70 | ``` 71 | This will help you to avoid magic in code. 72 | 73 | ## Default state 74 | 75 | When you add action to Redux Lazy you can set payload. 76 | Payload from all actions creates default state. 77 | 78 | If you need to customize it you can set default state: 79 | 80 | ```javascript 81 | const defaultState = { title: 'title', body: 'body' }; 82 | const rl = new RL('post', defaultState); 83 | ``` 84 | 85 | ## Documentation 86 | 87 | * [How to use](https://github.com/evheniy/redux-lazy/blob/master/docs/use.md) 88 | * [Types](https://github.com/evheniy/redux-lazy/blob/master/docs/types.md) 89 | * [Actions](https://github.com/evheniy/redux-lazy/blob/master/docs/actions.md) 90 | * [Reducer](https://github.com/evheniy/redux-lazy/blob/master/docs/reducer.md) 91 | * [Container](https://github.com/evheniy/redux-lazy/blob/master/docs/container.md) 92 | * [Options](https://github.com/evheniy/redux-lazy/blob/master/docs/options.md) 93 | 94 | [More examples](https://github.com/evheniy/redux-lazy/blob/master/tests/) 95 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-lazy", 3 | "version": "0.6.1", 4 | "description": "redux-lazy", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "lib" 8 | ], 9 | "scripts": { 10 | "test": "npm-run-all test:*", 11 | "test:security": "nsp check", 12 | "test:lint": "eslint . --ext .js,.jsx", 13 | "test:coverage": "cross-env NODE_ENV=test nyc mocha tests/*.{js,jsx}", 14 | "report": "cat ./coverage/lcov.info | coveralls", 15 | "build": "cross-env NODE_ENV=production gulp", 16 | "precommit": "npm t", 17 | "prepush": "npm t", 18 | "release": "npm run build && npm publish" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/evheniy/redux-lazy.git" 23 | }, 24 | "keywords": [ 25 | "redux", 26 | "react", 27 | "lazy", 28 | "action", 29 | "creator", 30 | "types", 31 | "reduce", 32 | "container" 33 | ], 34 | "author": "Evheniy Bystrov", 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/evheniy/redux-lazy/issues" 38 | }, 39 | "homepage": "https://github.com/evheniy/redux-lazy#readme", 40 | "peerDependencies": { 41 | "react-redux": "^5.0.7", 42 | "redux": "^4.0.0" 43 | }, 44 | "devDependencies": { 45 | "@babel/core": "^7.1.2", 46 | "@babel/plugin-proposal-class-properties": "^7.1.0", 47 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0", 48 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 49 | "@babel/preset-env": "^7.1.0", 50 | "@babel/preset-react": "^7.0.0", 51 | "@babel/register": "^7.0.0", 52 | "babel-eslint": "^10.0.1", 53 | "chai": "^4.2.0", 54 | "coveralls": "^3.0.2", 55 | "enzyme": "^3.7.0", 56 | "enzyme-adapter-react-16": "^1.6.0", 57 | "eslint": "^5.6.1", 58 | "eslint-config-airbnb": "^17.1.0", 59 | "eslint-plugin-import": "^2.14.0", 60 | "eslint-plugin-jsx-a11y": "^6.1.2", 61 | "eslint-plugin-react": "^7.11.1", 62 | "gulp": "^4.0.0", 63 | "gulp-babel": "^8.0.0", 64 | "gulp-clean-dest": "^0.2.0", 65 | "gulp-react": "^3.1.0", 66 | "husky": "^1.1.1", 67 | "jsdom": "^12.2.0", 68 | "mocha": "^5.2.0", 69 | "npm-run-all": "^4.1.3", 70 | "nsp": "^3.2.1", 71 | "nyc": "^13.1.0", 72 | "react": "^16.5.2", 73 | "react-dom": "^16.5.2", 74 | "react-redux": "^5.0.7", 75 | "redux": "^4.0.0", 76 | "redux-mock-store": "^1.5.3", 77 | "sinon": "^6.3.5" 78 | }, 79 | "dependencies": { 80 | "cross-env": "^5.2.0" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /docs/container.md: -------------------------------------------------------------------------------- 1 | # Container 2 | 3 | To get state from store and put it to React components you should use **[react-redux](https://github.com/reduxjs/react-redux)** library. 4 | It has **[connect](https://github.com/reduxjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)** - high order component (HOC) to get part of store and put it to component. 5 | 6 | ## Redux 7 | 8 | ```javascript 9 | import { connect } from 'react-redux'; 10 | import * as actions from './actions'; 11 | 12 | export const POST = '@@post/POST'; 13 | 14 | const mapStateToProps = state => state[POST]; 15 | const mapDispatchToProps = { ...actions }; 16 | 17 | export default connect(mapStateToProps, mapDispatchToProps); 18 | ``` 19 | 20 | Here we have 3 main points: 21 | 22 | * We need to create constant (POST) - it's useful for working with **[combineReducers](https://redux.js.org/basics/reducers#splitting-reducers)** and making selectors for **[mapStateToProps](https://github.com/reduxjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)**. 23 | * We need to create selector and put it to **[mapStateToProps](https://github.com/reduxjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)**. 24 | * We need to create **[mapDispatchToProps](https://github.com/reduxjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)**. 25 | 26 | After that we can use **connect** to wrap React component and put part of state using **selectors**. 27 | 28 | ## Redux Lazy 29 | 30 | With Redux Lazy you don't need to make it manually. 31 | Create **rl.js** file inside of your module and put code like this: 32 | 33 | ```javascript 34 | import RL from 'redux-lazy'; 35 | 36 | const rl = new RL('post'); 37 | 38 | rl.addAction('title', { title: '' }); 39 | rl.addAction('body', { body: '' }); 40 | rl.addAction('submit'); 41 | 42 | export default rl; 43 | ``` 44 | 45 | Then import **rl** where you need it: 46 | 47 | ```javascript 48 | import rl from './rl'; 49 | 50 | const { 51 | nameSpace, 52 | Container, 53 | mapStateToProps, 54 | mapDispatchToProps, 55 | } = rl; 56 | ``` 57 | 58 | We can use **nameSpace** for selectors. 59 | 60 | 61 | ## Documentation 62 | 63 | * [Install](https://github.com/evheniy/redux-lazy/blob/master/docs/install.md) 64 | * [How to use](https://github.com/evheniy/redux-lazy/blob/master/docs/use.md) 65 | * [Types](https://github.com/evheniy/redux-lazy/blob/master/docs/types.md) 66 | * [Actions](https://github.com/evheniy/redux-lazy/blob/master/docs/actions.md) 67 | * [Reducer](https://github.com/evheniy/redux-lazy/blob/master/docs/reducer.md) 68 | * [Options](https://github.com/evheniy/redux-lazy/blob/master/docs/options.md) 69 | 70 | [More examples](https://github.com/evheniy/redux-lazy/blob/master/tests/container.jsx) 71 | -------------------------------------------------------------------------------- /docs/use.md: -------------------------------------------------------------------------------- 1 | # How to use 2 | 3 | ## Form 4 | 5 | If you need to submit form: 6 | 7 | ### Redux 8 | 9 | Action: 10 | ```javascript 11 | export const MODULE_SUBMIT = '@@module/SUBMIT'; 12 | 13 | export const submitAction = () => ({ 14 | type: MODULE_SUBMIT, 15 | }); 16 | ``` 17 | React: 18 | ```html 19 |
{ 20 | event.preventDefault(); 21 | props.submitAction(); 22 | }}> 23 | ``` 24 | 25 | ### Redux Lazy 26 | 27 | Action: 28 | ```javascript 29 | rl.addFormAction('submit'); 30 | ``` 31 | React: 32 | ```html 33 | 34 | ``` 35 | 36 | ## Form Element 37 | 38 | If you need to get value from form input (textarea or < input type="text" />): 39 | 40 | ### Redux 41 | 42 | Action: 43 | ```javascript 44 | export const MODULE_TITLE = '@@module/TITLE'; 45 | 46 | export const titleAction = (title) => ({ 47 | type: MODULE_SUBMIT, 48 | title, 49 | }); 50 | ``` 51 | React: 52 | ```html 53 | props.titleAction(event.target.value)} 56 | value={props.title} 57 | /> 58 | ``` 59 | 60 | ### Redux Lazy 61 | 62 | Action: 63 | ```javascript 64 | rl.addFormElementAction('title', 'defaultValue'); 65 | ``` 66 | React: 67 | ```html 68 | 73 | ``` 74 | 75 | ## Event 76 | 77 | If you need to get event, for example button click: 78 | 79 | ```javascript 80 | rl.addEventAction('event'); 81 | ``` 82 | React: 83 | ```html 84 |