├── .gitignore
├── Connector.js
├── GenerateReducer.js
├── README.md
├── index.js
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
--------------------------------------------------------------------------------
/Connector.js:
--------------------------------------------------------------------------------
1 | import { connect } from 'react-redux'
2 |
3 | export const FilterObjectKeys = (obj, predicate) =>
4 | Object.keys(obj)
5 | .filter(key => predicate(key))
6 | .reduce((res, key) => (res[key] = obj[key], res), {}) // eslint-disable-line
7 |
8 | export default function (Component, States = [], Actions = []) {
9 | const mapStateToProps = state => {
10 | const states = FilterObjectKeys(state, (key) => States.indexOf(key) > -1) || {}
11 | return states
12 | }
13 | const mapDispatchToProps = dispatch => {
14 | let actionMap = {}
15 | Actions.forEach(action => {
16 | actionMap[action.name] = (...args) => dispatch(action(...args))
17 | })
18 | return actionMap
19 | }
20 |
21 | const connected = connect(
22 | mapStateToProps,
23 | mapDispatchToProps
24 | )(Component)
25 |
26 | return connected
27 | }
28 |
--------------------------------------------------------------------------------
/GenerateReducer.js:
--------------------------------------------------------------------------------
1 | const buildState = (state, action) => {
2 | let data = { ...action }
3 | delete data.type
4 | const reduction = data.reducer ? data.reducer(state, data) : data
5 | if (Array.isArray(reduction)) {
6 | return reduction
7 | } else {
8 | return { ...state, ...reduction }
9 | }
10 | }
11 |
12 | export default function (type, defaultState, hook) {
13 | const handle = (state = defaultState, action) => {
14 | if (action.type === type) {
15 | const newState = buildState(state, action)
16 | return hook ? hook(newState, action) : newState
17 | }
18 |
19 | return state
20 | }
21 |
22 | return handle
23 | }
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Diluter
2 | An automatic Redux reducer, taking the pain out of Redux.
3 | ___
4 | ## Install
5 | ```
6 | npm i --save Diluter
7 | ```
8 |
9 | ## Usage
10 | ### Create a Store
11 | ```js
12 | import Diluter from 'Diluter'
13 |
14 | const defaultState = {
15 | USER: { name: '', id: 0 },
16 | FRIENDS: []
17 | }
18 |
19 | const store = Diluter(defaultStore)
20 | ReactDOM.render(
21 |
22 |
23 |
24 | , document.getElementById('root'))
25 | ```
26 |
27 | ### Connect a Component
28 | ```js
29 | import { Connector } from 'Diluter'
30 |
31 | class App extends Component {
32 | render() {
33 | return (
34 |
35 | Hello {this.props.USER.name}!
36 | You have {this.props.FRIENDS.length} friends.
37 |
38 | )
39 | }
40 | }
41 |
42 | // Connector takes 3 arguments:
43 | // 1. The React Component
44 | // 2. The keys of the store to pass as props
45 | // 3. Actions to be mapped with dispatch as props
46 | export default Connector(App, ['USER', 'FRIENDS'], [])
47 | ```
48 |
49 | ### Dispatching an Action
50 | ```js
51 | const setUserName = name => dispatch => {
52 | dispatch({
53 | type: 'USER', // The key to target in the store
54 | name // Automatically apply the name to the "USER" object
55 | })
56 | }
57 |
58 | class SetName extends Component {
59 | render() {
60 | return (
61 |
62 | Please choose a new name.
63 | this.props.setUserName(e.target.value)}
67 | />
68 |
69 | )
70 | }
71 | }
72 |
73 | // "setUserName" needs to recieve a dispatch function to
74 | // dispatch changes to the store. This is automatically
75 | // mapped to all functions passed in the 3rd argument,
76 | // after which they're passed to the component via props.
77 | export default Connector(SetName, ['USER'], [setUserName])
78 | ```
79 |
80 | ### Action with Custom Reducer
81 | ```js
82 | // In this case, friend is an object containing
83 | // arbitrary data about the user. Not
84 | const addFriend = friend => dispatch => {
85 | dispatch({
86 | type: 'FRIENDS',
87 | reducer: (state) => {
88 | // This function will determine the new state
89 | // of the "FRIENDS" object in the store instead
90 | // of the usual automatic reducer built into Diluter.
91 |
92 | // Append the friend object to the store (FREINDS object)
93 | return [...state, friend]
94 | }
95 | })
96 | }
97 | ```
98 |
99 | ### Hook into the Reducer
100 | ```js
101 | // The hook allows you to modify reductions after the
102 | // normal reducer but before it gets applied to the store.
103 | const hook = (newState, action) => {
104 | // Set a value with the key "lastAction" containing
105 | // the action in the store before applying it.
106 | return { ...newState, lastAction: action }
107 | }
108 | const store = Diluter(defaultState, hook)
109 | ```
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
2 | import thunk from 'redux-thunk'
3 | import GenerateReducer from './GenerateReducer'
4 | import Connector from './Connector'
5 |
6 | export default (defaultState, hook, customMiddlewares) => {
7 | const mappedReducers = {}
8 | Object.keys(defaultState).forEach(key => {
9 | mappedReducers[key] = GenerateReducer(key, defaultState[key], hook)
10 | })
11 |
12 | let reducers = combineReducers(mappedReducers)
13 | let middlewares = [thunk, ...customMiddlewares]
14 | let store = createStore(reducers, compose(
15 | applyMiddleware(...middlewares),
16 | window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : a => a
17 | ))
18 | return store
19 | }
20 |
21 | export { Connector, GenerateReducer }
22 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diluter",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@babel/runtime": {
8 | "version": "7.3.4",
9 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.4.tgz",
10 | "integrity": "sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g==",
11 | "requires": {
12 | "regenerator-runtime": "^0.12.0"
13 | }
14 | },
15 | "hoist-non-react-statics": {
16 | "version": "3.3.0",
17 | "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz",
18 | "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==",
19 | "requires": {
20 | "react-is": "^16.7.0"
21 | }
22 | },
23 | "invariant": {
24 | "version": "2.2.4",
25 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
26 | "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
27 | "requires": {
28 | "loose-envify": "^1.0.0"
29 | }
30 | },
31 | "js-tokens": {
32 | "version": "4.0.0",
33 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
34 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
35 | },
36 | "loose-envify": {
37 | "version": "1.4.0",
38 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
39 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
40 | "requires": {
41 | "js-tokens": "^3.0.0 || ^4.0.0"
42 | }
43 | },
44 | "object-assign": {
45 | "version": "4.1.1",
46 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
47 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
48 | },
49 | "prop-types": {
50 | "version": "15.7.2",
51 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
52 | "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
53 | "requires": {
54 | "loose-envify": "^1.4.0",
55 | "object-assign": "^4.1.1",
56 | "react-is": "^16.8.1"
57 | }
58 | },
59 | "react-is": {
60 | "version": "16.8.4",
61 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.4.tgz",
62 | "integrity": "sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA=="
63 | },
64 | "react-redux": {
65 | "version": "6.0.1",
66 | "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-6.0.1.tgz",
67 | "integrity": "sha512-T52I52Kxhbqy/6TEfBv85rQSDz6+Y28V/pf52vDWs1YRXG19mcFOGfHnY2HsNFHyhP+ST34Aih98fvt6tqwVcQ==",
68 | "requires": {
69 | "@babel/runtime": "^7.3.1",
70 | "hoist-non-react-statics": "^3.3.0",
71 | "invariant": "^2.2.4",
72 | "loose-envify": "^1.4.0",
73 | "prop-types": "^15.7.2",
74 | "react-is": "^16.8.2"
75 | }
76 | },
77 | "redux": {
78 | "version": "4.0.1",
79 | "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz",
80 | "integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==",
81 | "requires": {
82 | "loose-envify": "^1.4.0",
83 | "symbol-observable": "^1.2.0"
84 | }
85 | },
86 | "redux-thunk": {
87 | "version": "2.3.0",
88 | "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
89 | "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
90 | },
91 | "regenerator-runtime": {
92 | "version": "0.12.1",
93 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz",
94 | "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg=="
95 | },
96 | "symbol-observable": {
97 | "version": "1.2.0",
98 | "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
99 | "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diluter",
3 | "version": "1.0.2",
4 | "description": "An automatic Redux reducer, taking the pain out of Redux.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/mobooru/Diluter.git"
12 | },
13 | "keywords": [
14 | "Redux",
15 | "React",
16 | "Reducer"
17 | ],
18 | "author": "RekkyRek",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/mobooru/Diluter/issues"
22 | },
23 | "homepage": "https://github.com/mobooru/Diluter#readme",
24 | "dependencies": {
25 | "react-redux": "^6.0.1",
26 | "redux": "^4.0.1",
27 | "redux-thunk": "^2.3.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------