From cd3671b543f6c02d9315a56b40a098c4180f9dbb Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 25 Jan 2018 01:12:39 +0300 Subject: [PATCH 1/7] # v0.1.5 process --- README.md | 4 +- lib/action.js | 47 +++--- lib/config.js | 2 +- lib/reducer.js | 12 ++ src/action.js | 49 +++--- src/config.js | 2 +- src/index.js | 4 +- src/reducer.js | 13 ++ test/action.spec.js | 10 +- test/config.spec.js | 13 +- test/helper.spec.js | 2 +- test/selector.spec.js | 2 +- website/package.json | 60 ++++--- website/src/App.css | 60 ++++--- website/src/App.js | 62 ++++--- website/src/App.test.js | 12 +- website/src/DevTools.js | 4 +- website/src/RESTApi.js | 2 +- website/src/blog/actions.js | 4 +- website/src/blog/index.js | 18 +- website/src/blog/store.js | 4 +- .../src/delete-entity-from-state/actions.js | 34 ++++ website/src/delete-entity-from-state/index.js | 159 ++++++++++++++++++ .../src/delete-entity-from-state/reducer.js | 13 ++ .../src/delete-entity-from-state/schema.js | 26 +++ website/src/delete-entity-from-state/store.js | 39 +++++ website/src/different-entity-id/actions.js | 4 +- website/src/different-entity-id/index.js | 28 +-- website/src/different-entity-id/store.js | 4 +- website/src/index.css | 6 +- website/src/index.js | 12 +- website/src/logo.svg | 3 +- website/src/merged-actions-data/actions.js | 4 +- website/src/merged-actions-data/index.js | 14 +- website/src/merged-actions-data/store.js | 4 +- website/src/registerServiceWorker.js | 56 +++--- 36 files changed, 561 insertions(+), 231 deletions(-) create mode 100644 website/src/delete-entity-from-state/actions.js create mode 100644 website/src/delete-entity-from-state/index.js create mode 100644 website/src/delete-entity-from-state/reducer.js create mode 100644 website/src/delete-entity-from-state/schema.js create mode 100644 website/src/delete-entity-from-state/store.js diff --git a/README.md b/README.md index 8de1e2e..edb9598 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ActionCreator + ActionSelector, reducers are created automatically [coverage-report](https://edtoken.github.io/redux-tide/coverage/lcov-report/index.html) -[![Join the chat at https://gitter.im/practice-feature/redux-tide](https://badges.gitter.im/practice-feature/redux-tide.svg)](https://gitter.im/practice-feature/redux-tide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://gitter.im/practice-feature/redux-tide](https://badges.gitter.im/practice-feature/redux-tide.svg)](https://gitter.im/practice-feature/redux-tide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![npm version](https://badge.fury.io/js/redux-tide.svg)](https://badge.fury.io/js/redux-tide) [![Build Status](https://api.travis-ci.org/edtoken/redux-tide.svg?branch=master)](https://travis-ci.org/edtoken/redux-tide) @@ -96,7 +96,7 @@ npm install redux-thunk --save ------ ### Discussion You can connect to [Gitter chat room](https://gitter.im/practice-feature/redux-tide) -[![Join the chat at https://gitter.im/practice-feature/redux-tide](https://badges.gitter.im/practice-feature/redux-tide.svg)](https://gitter.im/practice-feature/redux-tide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://gitter.im/practice-feature/redux-tide](https://badges.gitter.im/practice-feature/redux-tide.svg)](https://gitter.im/practice-feature/redux-tide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ### Usage 1. You might install library diff --git a/lib/action.js b/lib/action.js index 726f6b9..7ff5de8 100644 --- a/lib/action.js +++ b/lib/action.js @@ -389,28 +389,31 @@ var makeAction = function makeAction(actionId, parentActionId, actionSchema, act }; }; - // /** - // * Clean entity from entity reducer - // * - // * @memberOf action.makeAction.Action - // * @type {Function} - // * - // * @example - // * store.dispatch(userLoginAction.clean()) - // * - // * @returns {Undefined} - returns None, only clear entity data - // */ - // this.action.clean = () => { - // return (dispatch, getState) => { - // dispatch({ - // time: new Date().getTime(), - // type: ACTION_CLEAN_TYPE_NAME, - // prefix: ACTION_TYPE_PREFIX, - // actionId: this.actionId, - // actionSchema: this.schema - // }) - // } - // } + /** + * Delete entity from entity reducer + * + * @memberOf action.makeAction.Action + * @type {Function} + * + * @example + * store.dispatch(userDeleteAction.delete()) + * + * @example + * store.dispatch(userDeleteAction.withPrefix(userId).delete()) + * + * @returns {Undefined} - returns None, only delete entity data + */ + this.action.delete = function () { + return function (dispatch, getState) { + dispatch({ + time: new Date().getTime(), + type: _config.ACTION_DELETE_TYPE_NAME, + prefix: _config.ACTION_TYPE_PREFIX, + actionId: _this.actionId, + actionSchema: _this.schema + }); + }; + }; return this.action; }; diff --git a/lib/config.js b/lib/config.js index c15190a..de498ed 100644 --- a/lib/config.js +++ b/lib/config.js @@ -83,7 +83,7 @@ var ACTION_EMPTY_TYPE_NAME = exports.ACTION_EMPTY_TYPE_NAME = ACTION_TYPE_PREFIX * @const * @type {String} */ -var ACTION_CLEAN_TYPE_NAME = exports.ACTION_CLEAN_TYPE_NAME = ACTION_TYPE_PREFIX + '-clean'; +var ACTION_DELETE_TYPE_NAME = exports.ACTION_DELETE_TYPE_NAME = ACTION_TYPE_PREFIX + '-clean'; /** * replaced default response mapper to callback diff --git a/lib/reducer.js b/lib/reducer.js index 7f13aac..04c33da 100644 --- a/lib/reducer.js +++ b/lib/reducer.js @@ -67,6 +67,12 @@ var makeActionsReducer = function makeActionsReducer(defaultActionsState) { actionState = state.get(actionId); } + // delete entity id from actions + if (action.type === _config.ACTION_DELETE_TYPE_NAME) { + console.log('action delete', actionState); + return state; + } + actionState = actionState.merge({ status: status, time: time, @@ -121,6 +127,12 @@ var makeEntitiesReducer = function makeEntitiesReducer(defaultEntitiesState) { var newEntitiesItems = normalizedPayloadSource ? normalizedPayloadSource.entities : {}; + // delete entity id from actions + if (action.type === _config.ACTION_DELETE_TYPE_NAME) { + console.log('reducer delete'); + return state; + } + // merge entity item data for (var entityName in newEntitiesItems) { for (var entityId in newEntitiesItems[entityName]) { diff --git a/src/action.js b/src/action.js index 2fd9a61..54540fd 100644 --- a/src/action.js +++ b/src/action.js @@ -3,8 +3,8 @@ */ import { + ACTION_DELETE_TYPE_NAME, ACTION_EMPTY_TYPE_NAME, - ACTION_CLEAN_TYPE_NAME, ACTION_ID_KEY, ACTION_IDS_KEY, ACTION_TYPE_PREFIX, @@ -447,28 +447,31 @@ const makeAction = function( } } - // /** - // * Clean entity from entity reducer - // * - // * @memberOf action.makeAction.Action - // * @type {Function} - // * - // * @example - // * store.dispatch(userLoginAction.clean()) - // * - // * @returns {Undefined} - returns None, only clear entity data - // */ - // this.action.clean = () => { - // return (dispatch, getState) => { - // dispatch({ - // time: new Date().getTime(), - // type: ACTION_CLEAN_TYPE_NAME, - // prefix: ACTION_TYPE_PREFIX, - // actionId: this.actionId, - // actionSchema: this.schema - // }) - // } - // } + /** + * Delete entity from entity reducer + * + * @memberOf action.makeAction.Action + * @type {Function} + * + * @example + * store.dispatch(userDeleteAction.delete()) + * + * @example + * store.dispatch(userDeleteAction.withPrefix(userId).delete()) + * + * @returns {Undefined} - returns None, only delete entity data + */ + this.action.delete = () => { + return (dispatch, getState) => { + dispatch({ + time: new Date().getTime(), + type: ACTION_DELETE_TYPE_NAME, + prefix: ACTION_TYPE_PREFIX, + actionId: this.actionId, + actionSchema: this.schema + }) + } + } return this.action } diff --git a/src/config.js b/src/config.js index a92a4b0..942f9c5 100644 --- a/src/config.js +++ b/src/config.js @@ -78,7 +78,7 @@ export const ACTION_EMPTY_TYPE_NAME = `${ACTION_TYPE_PREFIX}-empty` * @const * @type {String} */ -export const ACTION_CLEAN_TYPE_NAME = `${ACTION_TYPE_PREFIX}-clean` +export const ACTION_DELETE_TYPE_NAME = `${ACTION_TYPE_PREFIX}-clean` /** * replaced default response mapper to callback diff --git a/src/index.js b/src/index.js index 12fc961..41f13e9 100644 --- a/src/index.js +++ b/src/index.js @@ -3,11 +3,11 @@ import { createReducers } from './reducer' import { denomalizeEntityItemById, getActionData, - getMergedActionsData, getEntityItemsByAction, getEntityItemsByEntityName, getEntityItemsBySchema, - getEntityReducer + getEntityReducer, + getMergedActionsData } from './selector' import { diff --git a/src/reducer.js b/src/reducer.js index 2780fb0..ed21c27 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -6,6 +6,7 @@ import { fromJS } from 'immutable' import { normalize } from 'normalizr' import { + ACTION_DELETE_TYPE_NAME, ACTION_EMPTY_TYPE_NAME, ACTION_TYPE_PREFIX, ACTIONS_REDUCER_NAME, @@ -67,6 +68,12 @@ const makeActionsReducer = defaultActionsState => { actionState = state.get(actionId) } + // delete entity id from actions + if (action.type === ACTION_DELETE_TYPE_NAME) { + console.log('action delete', actionState) + return state + } + actionState = actionState.merge({ status, time, @@ -136,6 +143,12 @@ const makeEntitiesReducer = defaultEntitiesState => { ? normalizedPayloadSource.entities : {} + // delete entity id from actions + if (action.type === ACTION_DELETE_TYPE_NAME) { + console.log('reducer delete') + return state + } + // merge entity item data for (let entityName in newEntitiesItems) { for (let entityId in newEntitiesItems[entityName]) { diff --git a/test/action.spec.js b/test/action.spec.js index 7f75bad..678da6b 100644 --- a/test/action.spec.js +++ b/test/action.spec.js @@ -1,16 +1,14 @@ import 'should' import sinon from 'sinon' import { schema } from 'normalizr' - -require('should-sinon') - import { + createAction, makeActionHandler, - makeActionUniqId, - makeAction, - createAction + makeActionUniqId } from '../src/action' +require('should-sinon') + describe('action makeActionUniqId ', function() { it('makeActionUniqId returns uniquie ids', function() { const result = new Set([ diff --git a/test/config.spec.js b/test/config.spec.js index 6104f83..28f2406 100644 --- a/test/config.spec.js +++ b/test/config.spec.js @@ -1,24 +1,23 @@ import 'should' import sinon from 'sinon' import { schema } from 'normalizr' - -require('should-sinon') - import { - IS_TEST_ENVIRONMENT, - STATUSES, + ACTION_EMPTY_TYPE_NAME, ACTION_ID_KEY, ACTION_IDS_KEY, ACTION_TYPE_PREFIX, ACTIONS_REDUCER_NAME, ENTITIES_REDUCER_NAME, - ACTION_EMPTY_TYPE_NAME, + IS_TEST_ENVIRONMENT, setDefaultResponseMapper, - setDenormalize + setDenormalize, + STATUSES } from '../src/config' import { createAction } from '../src/action' +require('should-sinon') + describe('config is valid', function() { it('should define all required variables', function() { IS_TEST_ENVIRONMENT.should.not.be.undefined() diff --git a/test/helper.spec.js b/test/helper.spec.js index ed1bdcd..7d11602 100644 --- a/test/helper.spec.js +++ b/test/helper.spec.js @@ -1,4 +1,4 @@ -import { uniqPrefix, parseError } from '../src/helper' +import { parseError, uniqPrefix } from '../src/helper' describe('helper uniqPrefix', function() { it('created uniq prefixed', function() { diff --git a/test/selector.spec.js b/test/selector.spec.js index cf27dec..a6e8b0f 100644 --- a/test/selector.spec.js +++ b/test/selector.spec.js @@ -2,7 +2,7 @@ import 'should' import { schema } from 'normalizr' import { fromJS } from 'immutable' -import { ENTITIES_REDUCER_NAME, ACTIONS_REDUCER_NAME } from '../src/config' +import { ACTIONS_REDUCER_NAME, ENTITIES_REDUCER_NAME } from '../src/config' import { getActionData, getEntityItemsByAction, diff --git a/website/package.json b/website/package.json index 6f17121..978e5f6 100644 --- a/website/package.json +++ b/website/package.json @@ -3,32 +3,13 @@ "version": "0.1.0", "private": true, "dependencies": { - "autoprefixer": "7.1.6", - "babel-core": "6.26.0", - "babel-eslint": "7.2.3", - "babel-jest": "20.0.3", - "babel-loader": "7.1.2", - "babel-preset-react-app": "^3.1.0", - "babel-runtime": "6.26.0", + "axios": "^0.17.1", + "redux-tide": "^0.1.4", "case-sensitive-paths-webpack-plugin": "2.1.1", "chalk": "1.1.3", - "css-loader": "0.28.7", "dotenv": "4.0.0", - "eslint": "4.10.0", - "eslint-config-react-app": "^2.0.1", - "eslint-loader": "1.9.0", - "eslint-plugin-flowtype": "2.39.1", - "eslint-plugin-import": "2.8.0", - "eslint-plugin-jsx-a11y": "5.1.1", - "eslint-plugin-react": "7.4.0", - "extract-text-webpack-plugin": "3.0.2", - "file-loader": "1.1.5", "fs-extra": "3.0.1", "history": "^4.7.2", - "html-loader": "^0.5.4", - "html-webpack-plugin": "2.29.0", - "jest": "20.0.4", - "markdown-loader": "^2.0.2", "normalizr": "^3.2.4", "object-assign": "4.1.1", "postcss-flexbugs-fixes": "3.2.0", @@ -46,12 +27,6 @@ "redux-devtools-dock-monitor": "^1.1.3", "redux-devtools-log-monitor": "^1.4.0", "redux-thunk": "^2.2.0", - "style-loader": "0.19.0", - "sw-precache-webpack-plugin": "0.11.4", - "url-loader": "0.6.2", - "webpack": "3.8.1", - "webpack-dev-server": "2.9.4", - "webpack-manifest-plugin": "1.3.2", "whatwg-fetch": "2.0.3" }, "scripts": { @@ -59,7 +34,36 @@ "build": "node scripts/build.js", "test": "node scripts/test.js --env=jsdom" }, - "devDependencies": {}, + "devDependencies": { + "codesandbox": "^1.1.14", + "autoprefixer": "7.1.6", + "babel-core": "6.26.0", + "babel-eslint": "7.2.3", + "babel-jest": "20.0.3", + "babel-loader": "7.1.2", + "babel-preset-react-app": "^3.1.0", + "babel-runtime": "6.26.0", + "eslint": "4.10.0", + "eslint-config-react-app": "^2.0.1", + "eslint-loader": "1.9.0", + "eslint-plugin-flowtype": "2.39.1", + "eslint-plugin-import": "2.8.0", + "eslint-plugin-jsx-a11y": "5.1.1", + "eslint-plugin-react": "7.4.0", + "style-loader": "0.19.0", + "sw-precache-webpack-plugin": "0.11.4", + "url-loader": "0.6.2", + "webpack": "3.8.1", + "webpack-dev-server": "2.9.4", + "webpack-manifest-plugin": "1.3.2", + "css-loader": "0.28.7", + "extract-text-webpack-plugin": "3.0.2", + "file-loader": "1.1.5", + "html-loader": "^0.5.4", + "html-webpack-plugin": "2.29.0", + "markdown-loader": "^2.0.2", + "jest": "20.0.4" + }, "jest": { "collectCoverageFrom": [ "src/**/*.{js,jsx,mjs}" diff --git a/website/src/App.css b/website/src/App.css index 8456cbf..9eaeb28 100644 --- a/website/src/App.css +++ b/website/src/App.css @@ -1,30 +1,34 @@ .App { - text-align: center; + text-align: center; } .App-logo { - animation: App-logo-spin infinite 20s linear; - height: 80px; + animation: App-logo-spin infinite 20s linear; + height: 80px; } .App-header { - background-color: #222; - height: 150px; - padding: 20px; - color: white; + background-color: #222; + height: 150px; + padding: 20px; + color: white; } .App-title { - font-size: 1.5em; + font-size: 1.5em; } .App-intro { - font-size: large; + font-size: large; } @keyframes App-logo-spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } .spinner { @@ -55,18 +59,23 @@ } @-webkit-keyframes sk-bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0) } - 40% { -webkit-transform: scale(1.0) } + 0%, 80%, 100% { + -webkit-transform: scale(0) + } + 40% { + -webkit-transform: scale(1.0) + } } @keyframes sk-bouncedelay { 0%, 80%, 100% { -webkit-transform: scale(0); transform: scale(0); - } 40% { - -webkit-transform: scale(1.0); - transform: scale(1.0); - } + } + 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } } .spinner { @@ -97,16 +106,21 @@ } @-webkit-keyframes sk-bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0) } - 40% { -webkit-transform: scale(1.0) } + 0%, 80%, 100% { + -webkit-transform: scale(0) + } + 40% { + -webkit-transform: scale(1.0) + } } @keyframes sk-bouncedelay { 0%, 80%, 100% { -webkit-transform: scale(0); transform: scale(0); - } 40% { - -webkit-transform: scale(1.0); - transform: scale(1.0); - } + } + 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } } \ No newline at end of file diff --git a/website/src/App.js b/website/src/App.js index 0a00b8f..4bac8a4 100644 --- a/website/src/App.js +++ b/website/src/App.js @@ -1,23 +1,40 @@ -import React, {Component} from 'react'; -import logo from './logo.svg'; -import {Navbar, Nav, NavItem} from 'react-bootstrap' -import './App.css'; +import React, {Component} from 'react' +import logo from './logo.svg' +import {Nav, Navbar, NavItem} from 'react-bootstrap' +import './App.css' const README = require('../../README.md') const exampleName = document.location.search.replace('?ex=', '') -const PUBLIC_URL = process.env.PUBLIC_URL || '/' +const PUBLIC_URL = (document && document.location && document.location.host === 'localhost:3000') ? process.env.PUBLIC_URL || '/' : 'https://edtoken.github.io/redux-tide' -const exampleComponents = { - 'blog': require('./blog'), - 'different-entity-id': require('./different-entity-id'), - 'merged-actions-data': require('./merged-actions-data') -} +const EXAMPLES = [ + { + 'title': 'Blog example', + 'path': 'blog', + 'component': require('./blog') + }, + { + 'title': 'Different entity id', + 'path': 'different-entity-id', + 'component': require('./different-entity-id') + }, + { + 'title': 'Merged actions data', + 'path': 'merged-actions-data', + 'component': require('./merged-actions-data') + }, + { + 'title': 'Delete entity from state', + 'path': 'delete-entity-from-state', + 'component': require('./delete-entity-from-state') + } +] class App extends Component { render() { - const ExampleComponent = exampleName && exampleComponents[exampleName] ? exampleComponents[exampleName].default : undefined + const ExampleComponent = exampleName ? EXAMPLES.find(item => item.path === exampleName).component.default : undefined return (
@@ -30,11 +47,11 @@ class App extends Component { Star + aria-label="Star @edtoken/redux-tide on GitHub">Star
@@ -53,15 +70,12 @@ class App extends Component { Index - - Blog example - - - Different entity id - - - Merged actions data - + {EXAMPLES.map((item, num) => { + return + {item.title} + + })}
@@ -87,8 +101,8 @@ class App extends Component { } - ); + ) } } -export default App; +export default App diff --git a/website/src/App.test.js b/website/src/App.test.js index b84af98..e639a62 100644 --- a/website/src/App.test.js +++ b/website/src/App.test.js @@ -1,8 +1,8 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; +import React from 'react' +import ReactDOM from 'react-dom' +import App from './App' it('renders without crashing', () => { - const div = document.createElement('div'); - ReactDOM.render(, div); -}); + const div = document.createElement('div') + ReactDOM.render(, div) +}) diff --git a/website/src/DevTools.js b/website/src/DevTools.js index 5459367..07457ca 100644 --- a/website/src/DevTools.js +++ b/website/src/DevTools.js @@ -1,4 +1,4 @@ -import React, {Component} from 'react' +import React from 'react' import {createDevTools} from 'redux-devtools' import LogMonitor from 'redux-devtools-log-monitor' import DockMonitor from 'redux-devtools-dock-monitor' @@ -8,7 +8,7 @@ export default createDevTools( diff --git a/website/src/RESTApi.js b/website/src/RESTApi.js index df872e5..d4384eb 100644 --- a/website/src/RESTApi.js +++ b/website/src/RESTApi.js @@ -5,7 +5,7 @@ const apiInstance = axios.create({ }) const createRequest = method => { - return function(url, params = {}, data = {}) { + return function (url, params = {}, data = {}) { return apiInstance.request({ method, url: url, diff --git a/website/src/blog/actions.js b/website/src/blog/actions.js index 0809914..bec1a63 100644 --- a/website/src/blog/actions.js +++ b/website/src/blog/actions.js @@ -1,6 +1,6 @@ -import {createAction} from "../../../src/action"; +import {createAction} from 'redux-tide' import * as api from '../RESTApi' -import {postsSchema} from "./schema"; +import {postsSchema} from "./schema" /** * Ajax axios call get all posts diff --git a/website/src/blog/index.js b/website/src/blog/index.js index 93c4b0d..769e6d8 100644 --- a/website/src/blog/index.js +++ b/website/src/blog/index.js @@ -1,15 +1,15 @@ -import React, {Component} from 'react'; -import {Provider} from 'react-redux' -import {connect} from 'react-redux' +import React, {Component} from 'react' +import {connect, Provider} from 'react-redux' import {ConnectedRouter} from 'react-router-redux' -import {Table, Pager, Modal, Button, FormControl, ControlLabel, Alert} from 'react-bootstrap' -import {Spinner} from "../Spinner"; +import {Alert, Button, ControlLabel, FormControl, Modal, Pager, Table} from 'react-bootstrap' +import {Spinner} from "../Spinner" -import DevTools from '../DevTools' import store, {history} from './store' -import {getAllPost, fetchPost, updatePost} from "./actions"; -import {getActionData} from "../../../src"; + +import DevTools from '../DevTools' +import {fetchPost, getAllPost, updatePost} from "./actions" +import {getActionData} from 'redux-tide' class BlogPostFormComponent extends Component { @@ -291,7 +291,7 @@ class BlogExampleComponent extends Component {
Please look into the DevTools panel and Network requests
-
You can hide DevTools, click Ctrl+H +
You can open DevTools, click Ctrl+H `posts/${postId}` +) + +export const updatePost = createAction( + postsSchema, + api.put, + (postId, data) => [ + `posts/${postId}`, + undefined, + data + ] +) + + +export const deletePost = createAction( + postsSchema, + api.del, + postId => `posts/${postId}` +) \ No newline at end of file diff --git a/website/src/delete-entity-from-state/index.js b/website/src/delete-entity-from-state/index.js new file mode 100644 index 0000000..20cbbb9 --- /dev/null +++ b/website/src/delete-entity-from-state/index.js @@ -0,0 +1,159 @@ +import React, {Component} from 'react' +import {connect, Provider} from 'react-redux' + +import {ConnectedRouter} from 'react-router-redux' +import {Alert} from 'react-bootstrap' + +import DevTools from '../DevTools' +import store, {history} from './store' +import {deletePost, fetchPost, updatePost} from "./actions" +import {getMergedActionsData} from 'redux-tide' + +class CommonPostComponent extends Component { + + componentWillMount() { + this.props.fetch(this.props.postId) + } + + componentWillReceiveProps(nextProps) { + const prevProps = this.props + this.props = nextProps + + if (this.props.postId && this.props.postId !== prevProps.postId) { + this.props.fetch(this.props.postId) + } + } + + render() { + const {postId, payload, isFetching, hasError, errorText} = this.props + + return (
+ POST ID (props) {postId} 
+ post id payload {payload ? payload.id : ''} +
+
+ + {isFetching &&
isFetching...
} + + + +   + +   + +
+
+ {hasError &&
{errorText}
} +
{JSON.stringify(payload, null, 2)}
+
) + } +} + +const CommonPost = connect( + (state, props) => getMergedActionsData( + fetchPost.withPrefix(props.postId), + updatePost.withPrefix(props.postId), + deletePost.withPrefix(props.postId) + ), + (dispatch) => ({ + del: postId => dispatch(deletePost.withPrefix(postId)(postId)), + fetch: postId => dispatch(fetchPost.withPrefix(postId)(postId)), + update: (postId, data) => dispatch(updatePost.withPrefix(postId)(postId, data)) + }) +)(CommonPostComponent) + +class PostsListComponent extends Component { + + render() { + return (
+

Posts List

+
) + } +} + +const PostsList = connect( + (state, props) => ({}), + (dispatch) => ({}) +)(PostsListComponent) + +class PostsTableComponent extends Component { + render() { + return (
+

Posts Table

+
) + } +} + +const PostsTable = connect( + (state, props) => ({}), + (dispatch) => ({}) +)(PostsTableComponent) + +class DeleteTntityFromStateExampleComponent extends Component { + + constructor(props) { + super(props) + } + + render() { + + return (
+

Delete Entity from state

+

Source code source +

+ + + Demonstrate how to use `dispatch(action.delete())` method
+
+ +
+
+

With delete It's correct

+ +
+ +
+ +
+
+

Without delete It's no correct

+ +
+ +
+ +
+
+
) + } +} + +export default class MergedActionsDataComponentWrapper extends Component { + + render() { + return (
+ + +
+ + +
+
+
+
) + } +} \ No newline at end of file diff --git a/website/src/delete-entity-from-state/reducer.js b/website/src/delete-entity-from-state/reducer.js new file mode 100644 index 0000000..b9abc22 --- /dev/null +++ b/website/src/delete-entity-from-state/reducer.js @@ -0,0 +1,13 @@ +/** + * + * Common reducer with your data + * + */ +const defaultState = { + NODE_ENV: process.env.NODE_ENV +} + +export const customReducer = (state = defaultState, action) => { + + return state +} \ No newline at end of file diff --git a/website/src/delete-entity-from-state/schema.js b/website/src/delete-entity-from-state/schema.js new file mode 100644 index 0000000..a8130ed --- /dev/null +++ b/website/src/delete-entity-from-state/schema.js @@ -0,0 +1,26 @@ +import {schema} from 'normalizr' + +const profileSchema = new schema.Entity('profile') +const commentsSchema = new schema.Entity('comments') +const postsSchema = new schema.Entity('posts') + +postsSchema.define({ + // author: profileSchema, + // comments: [commentsSchema] +}) + +commentsSchema.define({ + // postId: postsSchema +}) + +export { + profileSchema, + commentsSchema, + postsSchema +} + +export const appSchema = { + profileSchema, + commentsSchema, + postsSchema +} \ No newline at end of file diff --git a/website/src/delete-entity-from-state/store.js b/website/src/delete-entity-from-state/store.js new file mode 100644 index 0000000..c995c07 --- /dev/null +++ b/website/src/delete-entity-from-state/store.js @@ -0,0 +1,39 @@ +import {applyMiddleware, combineReducers, compose, createStore} from 'redux' +import {routerMiddleware} from 'react-router-redux' +import {denormalize} from 'normalizr' +import thunk from 'redux-thunk' +import createHistory from 'history/createBrowserHistory' +import {createReducers, setDefaultResponseMapper, setDenormalize} from 'redux-tide' +import DevTools from '../DevTools' +import {customReducer} from './reducer' +import {appSchema} from './schema' + +setDefaultResponseMapper((resp) => { + return resp.data +}) + +setDenormalize(denormalize) + +export const history = createHistory() + +const rootInitialState = {} +const enhancers = [] +const middleware = [ + thunk, + routerMiddleware(history) +] + +enhancers.push(DevTools.instrument()) + +const composedEnhancers = compose( + applyMiddleware(...middleware), + ...enhancers +) +export default createStore( + combineReducers({ + custom: customReducer, + ...createReducers(...appSchema) + }), + rootInitialState, + composedEnhancers +) \ No newline at end of file diff --git a/website/src/different-entity-id/actions.js b/website/src/different-entity-id/actions.js index ec4e120..6ecbca2 100644 --- a/website/src/different-entity-id/actions.js +++ b/website/src/different-entity-id/actions.js @@ -1,6 +1,6 @@ -import {createAction} from "../../../src/action"; +import {createAction} from 'redux-tide' import * as api from '../RESTApi' -import {postsSchema} from "./schema"; +import {postsSchema} from "./schema" /** diff --git a/website/src/different-entity-id/index.js b/website/src/different-entity-id/index.js index 61b64be..604346e 100644 --- a/website/src/different-entity-id/index.js +++ b/website/src/different-entity-id/index.js @@ -1,25 +1,23 @@ -import React, {Component} from 'react'; -import {Provider} from 'react-redux' -import {connect} from 'react-redux' +import React, {Component} from 'react' +import {connect, Provider} from 'react-redux' import {ConnectedRouter} from 'react-router-redux' -import {Table, Pager, ProgressBar, Modal, Button, FormControl, ControlLabel, Alert} from 'react-bootstrap' +import {Alert} from 'react-bootstrap' import DevTools from '../DevTools' import store, {history} from './store' -import {fetchPost, fetchSinglePost, updatePost, updateSinglePost} from "./actions"; -import {getActionData} from "../../../src"; +import {fetchPost, fetchSinglePost, updatePost, updateSinglePost} from "./actions" +import {getActionData} from 'redux-tide' class CommonPostComponent extends Component { componentWillMount() { - console.log('fetch', this.props.postId) this.props.fetch(this.props.postId) } componentWillReceiveProps(nextProps) { // it's need only for SinglePostCorrectComponent - const prevProps = this.props; + const prevProps = this.props this.props = nextProps if (this.props.postId && this.props.postId !== prevProps.postId) { @@ -62,8 +60,8 @@ class CommonPostComponent extends Component { const PostCorrectComponent = connect( (state, props) => getActionData(fetchPost.withPrefix(props.postId)), dispatch => ({ - fetch: (postId) => dispatch(fetchPost.withPrefix(postId)(postId)), - update: (postId, data) => dispatch(updatePost.withPrefix(postId)(postId, data)) + fetch: postId => dispatch(fetchPost.withPrefix(postId)(postId)), + update: (postId, data) => dispatch(updatePost.withPrefix(postId)(postId, data)), }) )(CommonPostComponent) @@ -79,8 +77,8 @@ const PostIncorrectComponent = connect( const SinglePostCorrectComponent = connect( state => getActionData(fetchSinglePost), dispatch => ({ - fetch: (postId) => dispatch(fetchSinglePost(postId)), - update: (postId, data) => (dispatch(updateSinglePost(postId, data))) + fetch: postId => dispatch(fetchSinglePost(postId)), + update: (postId, data) => dispatch(updateSinglePost(postId, data)) }) )(CommonPostComponent) @@ -113,7 +111,8 @@ class DifferentEntityIdExampleComponent extends Component { return (

Different entity Id

-

Source code source

+

Source code source

Demonstrate how to use `.withPrefix`, `.withName`, `.clone` methods
@@ -140,7 +139,8 @@ class DifferentEntityIdExampleComponent extends Component { If you are have 1 component to 1 action
you can use without withPrefix method, it's not required
- Please change postId from input to 2,
Then click update and look correct-post-2
+ Please change postId from input to 2,
Then click update + and look correct-post-2
, document.getElementById('root')); -// registerServiceWorker(); +ReactDOM.render(, document.getElementById('root')) diff --git a/website/src/logo.svg b/website/src/logo.svg index 6b60c10..4ec91df 100644 --- a/website/src/logo.svg +++ b/website/src/logo.svg @@ -1,6 +1,7 @@ - + diff --git a/website/src/merged-actions-data/actions.js b/website/src/merged-actions-data/actions.js index ff8702f..2c1358e 100644 --- a/website/src/merged-actions-data/actions.js +++ b/website/src/merged-actions-data/actions.js @@ -1,6 +1,6 @@ -import {createAction} from "../../../src/action"; +import {createAction} from 'redux-tide' import * as api from '../RESTApi' -import {postsSchema} from "./schema"; +import {postsSchema} from "./schema" /** diff --git a/website/src/merged-actions-data/index.js b/website/src/merged-actions-data/index.js index 168842b..2aa2884 100644 --- a/website/src/merged-actions-data/index.js +++ b/website/src/merged-actions-data/index.js @@ -1,14 +1,13 @@ -import React, {Component} from 'react'; -import {Provider} from 'react-redux' -import {connect} from 'react-redux' +import React, {Component} from 'react' +import {connect, Provider} from 'react-redux' import {ConnectedRouter} from 'react-router-redux' -import {Table, Pager, ProgressBar, Modal, Button, FormControl, ControlLabel, Alert} from 'react-bootstrap' +import {Alert} from 'react-bootstrap' import DevTools from '../DevTools' import store, {history} from './store' -import {fetchPost, fetchSinglePost, updatePost, updateSinglePost} from "./actions"; -import {getActionData, getMergedActionsData} from "../../../src"; +import {fetchPost, fetchSinglePost, updatePost, updateSinglePost} from "./actions" +import {getActionData, getMergedActionsData} from "../../../src" class CommonPostComponent extends Component { @@ -97,7 +96,8 @@ class DifferentEntityIdExampleComponent extends Component { return (

Merged Actions Data

-

Source code source

+

Source code source

Demonstrate how to use `getMergedActionsData` selector
diff --git a/website/src/merged-actions-data/store.js b/website/src/merged-actions-data/store.js index 806c7dc..c995c07 100644 --- a/website/src/merged-actions-data/store.js +++ b/website/src/merged-actions-data/store.js @@ -1,9 +1,9 @@ import {applyMiddleware, combineReducers, compose, createStore} from 'redux' import {routerMiddleware} from 'react-router-redux' -import {denormalize} from 'normalizr'; +import {denormalize} from 'normalizr' import thunk from 'redux-thunk' import createHistory from 'history/createBrowserHistory' -import {createReducers, setDefaultResponseMapper, setDenormalize} from '../../../src/index'; +import {createReducers, setDefaultResponseMapper, setDenormalize} from 'redux-tide' import DevTools from '../DevTools' import {customReducer} from './reducer' import {appSchema} from './schema' diff --git a/website/src/registerServiceWorker.js b/website/src/registerServiceWorker.js index 12542ba..9612a6c 100644 --- a/website/src/registerServiceWorker.js +++ b/website/src/registerServiceWorker.js @@ -10,36 +10,36 @@ const isLocalhost = Boolean( window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +) export default function register() { if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location); + const publicUrl = new URL(process.env.PUBLIC_URL, window.location) if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 - return; + return } window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` if (isLocalhost) { // This is running on localhost. Lets check if a service worker still exists or not. - checkValidServiceWorker(swUrl); + checkValidServiceWorker(swUrl) } else { // Is not local host. Just register service worker - registerValidSW(swUrl); + registerValidSW(swUrl) } - }); + }) } } @@ -48,7 +48,7 @@ function registerValidSW(swUrl) { .register(swUrl) .then(registration => { registration.onupdatefound = () => { - const installingWorker = registration.installing; + const installingWorker = registration.installing installingWorker.onstatechange = () => { if (installingWorker.state === 'installed') { if (navigator.serviceWorker.controller) { @@ -56,20 +56,20 @@ function registerValidSW(swUrl) { // the fresh content will have been added to the cache. // It's the perfect time to display a "New content is // available; please refresh." message in your web app. - console.log('New content is available; please refresh.'); + console.log('New content is available; please refresh.') } else { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); + console.log('Content is cached for offline use.') } } - }; - }; + } + } }) .catch(error => { - console.error('Error during service worker registration:', error); - }); + console.error('Error during service worker registration:', error) + }) } function checkValidServiceWorker(swUrl) { @@ -84,25 +84,25 @@ function checkValidServiceWorker(swUrl) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then(registration => { registration.unregister().then(() => { - window.location.reload(); - }); - }); + window.location.reload() + }) + }) } else { // Service worker found. Proceed as normal. - registerValidSW(swUrl); + registerValidSW(swUrl) } }) .catch(() => { console.log( 'No internet connection found. App is running in offline mode.' - ); - }); + ) + }) } export function unregister() { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready.then(registration => { - registration.unregister(); - }); + registration.unregister() + }) } } From dbe11c19968bc94826f59ee420330bdc26cf326f Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 25 Jan 2018 01:17:12 +0300 Subject: [PATCH 2/7] # v0.1.5 process --- website/src/merged-actions-data/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/src/merged-actions-data/index.js b/website/src/merged-actions-data/index.js index 2aa2884..f7419ac 100644 --- a/website/src/merged-actions-data/index.js +++ b/website/src/merged-actions-data/index.js @@ -96,7 +96,8 @@ class DifferentEntityIdExampleComponent extends Component { return (

Merged Actions Data

-

Source code Source code source

From 10c60bc9b978752fa4cc4ec6506bbb98a14f15e6 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 27 Jan 2018 13:13:31 +0300 Subject: [PATCH 3/7] # v0.1.5 process --- CHANGELOG.md | 20 ++++++++ README.md | 4 +- lib/selector.js | 11 +++-- package.json | 4 +- src/selector.js | 17 +++++-- test/selector.spec.js | 1 + website/public/index.html | 11 +++++ website/src/blog/actions.js | 6 +-- website/src/blog/index.js | 33 ++++++++----- website/src/blog/schema.js | 6 +-- .../src/delete-entity-from-state/actions.js | 4 +- website/src/delete-entity-from-state/index.js | 46 ++++--------------- .../src/delete-entity-from-state/schema.js | 6 +-- website/src/different-entity-id/actions.js | 6 +-- website/src/different-entity-id/index.js | 6 +++ website/src/different-entity-id/schema.js | 6 +-- website/src/merged-actions-data/actions.js | 4 +- website/src/merged-actions-data/index.js | 13 ++++-- website/src/merged-actions-data/schema.js | 6 +-- 19 files changed, 126 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a67f11d..9fd8ceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +# 0.1.5 +Change selector payload type of data, now it's *Immutable JSON or unndefined* please see [test-source](https://github.com/edtoken/redux-tide/blob/master/test/selector.spec.js#L48) +Implement `action.delete` functionality, for details please see [source](https://github.com/edtoken/redux-tide/blob/master/src/action.js#L464) and [example](https://edtoken.github.io/redux-tide/?ex=delete-entity-from-state) and [example-source](https://github.com/edtoken/redux-tide/blob/master/website/src/delete-entity-from-state/index.js#L1) +Improve documentation +Improve examples, add new example +Add code sandbox examples +Add new badges + +# 0.1.4 + +# 0.1.5 +Change selector payload type of data, now it's *Immutable JSON or unndefined* please see [test-source](https://github.com/edtoken/redux-tide/blob/master/test/selector.spec.js#L48) +Implement `action.delete` functionality, for details please see [source](https://github.com/edtoken/redux-tide/blob/master/src/action.js#L464) and [example](https://edtoken.github.io/redux-tide/?ex=delete-entity-from-state) and [example-source](https://github.com/edtoken/redux-tide/blob/master/website/src/delete-entity-from-state/index.js#L1) +Improve documentation +Improve examples, add new example +Add code sandbox examples +Add new badges + +# 0.1.4 + # 0.1.3 Fix critical bug in method `Action.empty` small refactoring action.js, selector.js files diff --git a/README.md b/README.md index edb9598..1e9a352 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,9 @@ ActionCreator + ActionSelector, reducers are created automatically [![Maintainability](https://api.codeclimate.com/v1/badges/5952e9edfa038e49658f/maintainability)](https://codeclimate.com/github/edtoken/redux-tide/maintainability) [![npm downloads](https://img.shields.io/npm/dm/redux-tide.svg?style=flat-square)](https://www.npmjs.com/package/redux-tide) [![Coverage Status](https://coveralls.io/repos/github/edtoken/redux-tide/badge.svg?branch=master)](https://coveralls.io/github/edtoken/redux-tide?branch=master) -[![Inline docs](https://inch-ci.org/github/edtoken/redux-tide.svg?branch=master)](https://inch-ci.org/github/edtoken/redux-tide) +[![Inline docs](https://inch-ci.org/github/edtoken/redux-tide.svg?branch=master)](https://inch-ci.org/github/edtoken/redux-tide) +[![dependencies Status](https://david-dm.org/edtoken/redux-tide/status.svg)](https://david-dm.org/edtoken/redux-tide) +[![devDependencies Status](https://david-dm.org/edtoken/redux-tide/dev-status.svg)](https://david-dm.org/edtoken/redux-tide?type=dev) [![HitCount](http://hits.dwyl.com/edtoken/redux-tide.svg)](http://hits.dwyl.com/edtoken/redux-tide) [![NPM](https://nodei.co/npm/redux-tide.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/redux-tide/) diff --git a/lib/selector.js b/lib/selector.js index 9e7d53c..312f85b 100644 --- a/lib/selector.js +++ b/lib/selector.js @@ -44,21 +44,21 @@ var getPayloadIds = function getPayloadIds(dataKey, isArray, actionState, stateK }; var makeActionDenormalizedPayload = function makeActionDenormalizedPayload(isArray, payloadIds, schema, entities) { + // return empty immutable object if (!payloadIds) { return undefined; } var result = (0, _helper.denormalize)(payloadIds, [schema], entities).filter(function (v) { return v; - }).map(function (item) { - return item.toJS(); }); + return isArray ? result : result[0]; }; var makeActionDenormalizedPayloads = function makeActionDenormalizedPayloads(isFetching, actionSchema, entities, payloadIsArray, actionDataKey, entityState, actionState) { if (!actionDataKey) { - return {}; + return undefined; } if (!entityState) { @@ -133,7 +133,10 @@ var getMergedActionsData = exports.getMergedActionsData = function getMergedActi }); return sortedByUpate.reduce(function (memo, item) { - return Object.assign(memo, item); + return Object.assign(memo, item, { + payload: memo.payload ? memo.payload.merge(item.payload) : item.payload, + prevPayload: memo.prevPayload ? memo.prevPayload.merge(item.prevPayload) : item.prevPayload + }); }); }); }; diff --git a/package.json b/package.json index 49c8693..63b182d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "redux-tide", "description": "tiny factory for redux crud normalize", - "version": "0.1.3", + "version": "0.1.5", "main": "./lib/index.js", "files": [ "lib", @@ -82,7 +82,7 @@ "jsdoc": "^3.5.5", "json-server": "^0.12.1", "minami": "^1.2.3", - "mocha": "^4.1.0", + "mocha": "^5.0.0", "prettier": "^1.9.2", "raw-loader": "^0.5.1", "react": "^16.2.0", diff --git a/src/selector.js b/src/selector.js index 1423b8d..1d181b5 100644 --- a/src/selector.js +++ b/src/selector.js @@ -46,13 +46,13 @@ const makeActionDenormalizedPayload = ( schema, entities ) => { + // return empty immutable object if (!payloadIds) { return undefined } - const result = denormalize(payloadIds, [schema], entities) - .filter(v => v) - .map(item => item.toJS()) + const result = denormalize(payloadIds, [schema], entities).filter(v => v) + return isArray ? result : result[0] } @@ -66,7 +66,7 @@ const makeActionDenormalizedPayloads = ( actionState ) => { if (!actionDataKey) { - return {} + return undefined } if (!entityState) { @@ -168,7 +168,14 @@ export const getMergedActionsData = (...actions) => { const sortedByUpate = actionsData.sort((a, b) => a.time - b.time) return sortedByUpate.reduce((memo, item) => { - return Object.assign(memo, item) + return Object.assign(memo, item, { + payload: memo.payload + ? memo.payload.merge(item.payload) + : item.payload, + prevPayload: memo.prevPayload + ? memo.prevPayload.merge(item.prevPayload) + : item.prevPayload + }) }) } ) diff --git a/test/selector.spec.js b/test/selector.spec.js index a6e8b0f..b03aadf 100644 --- a/test/selector.spec.js +++ b/test/selector.spec.js @@ -46,6 +46,7 @@ it('selector getActionData', function() { } const result = getActionData(action)(state) + result.payload = result.payload.toJS() result.should.be.deepEqual({ status: '', diff --git a/website/public/index.html b/website/public/index.html index c016007..1900e5b 100644 --- a/website/public/index.html +++ b/website/public/index.html @@ -1,6 +1,17 @@ + + + + + diff --git a/website/src/blog/actions.js b/website/src/blog/actions.js index bec1a63..1b6ca75 100644 --- a/website/src/blog/actions.js +++ b/website/src/blog/actions.js @@ -7,7 +7,7 @@ import {postsSchema} from "./schema" * * @type {Action} */ -export const getAllPost = createAction(postsSchema, api.get, query => [`posts`, query]) +export const getAllPost = createAction(postsSchema, api.get, query => [`posts?_embed=comments`, query]) /** @@ -17,10 +17,10 @@ export const getAllPost = createAction(postsSchema, api.get, query => [`posts`, * * @type {Action} */ -export const fetchPost = createAction(postsSchema, api.get, postId => `posts/${postId}`) +export const fetchPost = createAction(postsSchema, api.get, postId => `posts/${postId}?_embed=comments`) export const updatePost = createAction(postsSchema, api.put, (postId, data) => [ - `posts/${postId}`, + `posts/${postId}?_embed=comments`, undefined, data ]) diff --git a/website/src/blog/index.js b/website/src/blog/index.js index 769e6d8..c257a53 100644 --- a/website/src/blog/index.js +++ b/website/src/blog/index.js @@ -39,7 +39,7 @@ class BlogPostFormComponent extends Component { // return // } - this.setState({form: this.props.payload || {}}) + this.setState({form: this.props.payload ? this.props.payload.toJS() : {}}) } componentWillMount() { @@ -67,6 +67,8 @@ class BlogPostFormComponent extends Component { const disableEdit = isFetching const completed = saved && this.props.status === 'success' + console.log('payload', payload) + return (
@@ -88,9 +90,6 @@ class BlogPostFormComponent extends Component { But you are calling only PUT post/postId -

fetchPost payload:

-
{JSON.stringify(payload, null, 2)}
- {isFetching &&
} @@ -125,6 +124,11 @@ class BlogPostFormComponent extends Component { {!completed && 'Save changes'} + +
+

fetchPost payload:

+
{JSON.stringify(payload, null, 2)}
+
) @@ -212,11 +216,11 @@ class BlogPostsTableComponent extends Component { {hasPayload && payload.map((item, num) => { return this.props.handleOpenPost(item.id)}> - {item.userId} - {item.id} - {item.title} + key={['table-post', item.get('id'), num].join('-')} + onClick={() => this.props.handleOpenPost(item.get('id'))}> + {item.get('userId')} + {item.get('id')} + {item.get('title')} @@ -283,8 +287,15 @@ class BlogExampleComponent extends Component { return (

Blog Example

-

Source code source

+

+ Preview in SandBox codesandbox.io +

+ +

Source code source

Demonstrate how to create list and single item requests, sync data between it, witout reducers diff --git a/website/src/blog/schema.js b/website/src/blog/schema.js index a8130ed..4119a59 100644 --- a/website/src/blog/schema.js +++ b/website/src/blog/schema.js @@ -5,12 +5,12 @@ const commentsSchema = new schema.Entity('comments') const postsSchema = new schema.Entity('posts') postsSchema.define({ - // author: profileSchema, - // comments: [commentsSchema] + author: profileSchema, + comments: [commentsSchema] }) commentsSchema.define({ - // postId: postsSchema + postId: postsSchema }) export { diff --git a/website/src/delete-entity-from-state/actions.js b/website/src/delete-entity-from-state/actions.js index a313ea6..b13e3e8 100644 --- a/website/src/delete-entity-from-state/actions.js +++ b/website/src/delete-entity-from-state/actions.js @@ -13,14 +13,14 @@ import {postsSchema} from "./schema" export const fetchPost = createAction( postsSchema, api.get, - postId => `posts/${postId}` + postId => `posts/${postId}?_embed=comments` ) export const updatePost = createAction( postsSchema, api.put, (postId, data) => [ - `posts/${postId}`, + `posts/${postId}?_embed=comments`, undefined, data ] diff --git a/website/src/delete-entity-from-state/index.js b/website/src/delete-entity-from-state/index.js index 20cbbb9..128733a 100644 --- a/website/src/delete-entity-from-state/index.js +++ b/website/src/delete-entity-from-state/index.js @@ -56,7 +56,9 @@ class CommonPostComponent extends Component {

{hasError &&
{errorText}
} -
{JSON.stringify(payload, null, 2)}
+
{JSON.stringify({
+        title: payload ? payload.get('title') : ''
+      }, null, 2)}
) } } @@ -74,33 +76,6 @@ const CommonPost = connect( }) )(CommonPostComponent) -class PostsListComponent extends Component { - - render() { - return (
-

Posts List

-
) - } -} - -const PostsList = connect( - (state, props) => ({}), - (dispatch) => ({}) -)(PostsListComponent) - -class PostsTableComponent extends Component { - render() { - return (
-

Posts Table

-
) - } -} - -const PostsTable = connect( - (state, props) => ({}), - (dispatch) => ({}) -)(PostsTableComponent) - class DeleteTntityFromStateExampleComponent extends Component { constructor(props) { @@ -111,6 +86,13 @@ class DeleteTntityFromStateExampleComponent extends Component { return (

Delete Entity from state

+ +

+ Preview in SandBox codesandbox.io +

+

Source code source @@ -124,18 +106,10 @@ class DeleteTntityFromStateExampleComponent extends Component {

With delete It's correct

-
- -
-

Without delete It's no correct

-
- -
-
) diff --git a/website/src/delete-entity-from-state/schema.js b/website/src/delete-entity-from-state/schema.js index a8130ed..4119a59 100644 --- a/website/src/delete-entity-from-state/schema.js +++ b/website/src/delete-entity-from-state/schema.js @@ -5,12 +5,12 @@ const commentsSchema = new schema.Entity('comments') const postsSchema = new schema.Entity('posts') postsSchema.define({ - // author: profileSchema, - // comments: [commentsSchema] + author: profileSchema, + comments: [commentsSchema] }) commentsSchema.define({ - // postId: postsSchema + postId: postsSchema }) export { diff --git a/website/src/different-entity-id/actions.js b/website/src/different-entity-id/actions.js index 6ecbca2..f7d214c 100644 --- a/website/src/different-entity-id/actions.js +++ b/website/src/different-entity-id/actions.js @@ -13,14 +13,14 @@ import {postsSchema} from "./schema" export const fetchPost = createAction( postsSchema, api.get, - postId => `posts/${postId}` + postId => `posts/${postId}?_embed=comments` ) export const updatePost = createAction( postsSchema, api.put, (postId, data) => [ - `posts/${postId}`, + `posts/${postId}?_embed=comments`, undefined, data ] @@ -29,7 +29,7 @@ export const updatePost = createAction( export const deletePost = createAction( postsSchema, api.del, - postId => `posts/${postId}` + postId => `posts/${postId}?_embed=comments` ) diff --git a/website/src/different-entity-id/index.js b/website/src/different-entity-id/index.js index 604346e..5942077 100644 --- a/website/src/different-entity-id/index.js +++ b/website/src/different-entity-id/index.js @@ -111,6 +111,12 @@ class DifferentEntityIdExampleComponent extends Component { return (

Different entity Id

+

+ Preview in SandBox codesandbox.io +

+

Source code source

diff --git a/website/src/different-entity-id/schema.js b/website/src/different-entity-id/schema.js index a8130ed..4119a59 100644 --- a/website/src/different-entity-id/schema.js +++ b/website/src/different-entity-id/schema.js @@ -5,12 +5,12 @@ const commentsSchema = new schema.Entity('comments') const postsSchema = new schema.Entity('posts') postsSchema.define({ - // author: profileSchema, - // comments: [commentsSchema] + author: profileSchema, + comments: [commentsSchema] }) commentsSchema.define({ - // postId: postsSchema + postId: postsSchema }) export { diff --git a/website/src/merged-actions-data/actions.js b/website/src/merged-actions-data/actions.js index 2c1358e..f7ec697 100644 --- a/website/src/merged-actions-data/actions.js +++ b/website/src/merged-actions-data/actions.js @@ -13,14 +13,14 @@ import {postsSchema} from "./schema" export const fetchPost = createAction( postsSchema, api.get, - postId => `posts/${postId}` + postId => `posts/${postId}?_embed=comments` ) export const updatePost = createAction( postsSchema, api.put, (postId, data) => [ - `posts/${postId}`, + `posts/${postId}?_embed=comments`, undefined, data ] diff --git a/website/src/merged-actions-data/index.js b/website/src/merged-actions-data/index.js index f7419ac..0f5c546 100644 --- a/website/src/merged-actions-data/index.js +++ b/website/src/merged-actions-data/index.js @@ -6,13 +6,13 @@ import {Alert} from 'react-bootstrap' import DevTools from '../DevTools' import store, {history} from './store' -import {fetchPost, fetchSinglePost, updatePost, updateSinglePost} from "./actions" -import {getActionData, getMergedActionsData} from "../../../src" + +import {fetchPost, fetchSinglePost, updatePost, updateSinglePost} from './actions' +import {getActionData, getMergedActionsData} from 'redux-tide' class CommonPostComponent extends Component { componentWillMount() { - console.log('fetch', this.props.postId) this.props.fetch(this.props.postId) } @@ -96,6 +96,13 @@ class DifferentEntityIdExampleComponent extends Component { return (

Merged Actions Data

+ +

+ Preview in SandBox codesandbox.io +

+

Source code source

diff --git a/website/src/merged-actions-data/schema.js b/website/src/merged-actions-data/schema.js index a8130ed..4119a59 100644 --- a/website/src/merged-actions-data/schema.js +++ b/website/src/merged-actions-data/schema.js @@ -5,12 +5,12 @@ const commentsSchema = new schema.Entity('comments') const postsSchema = new schema.Entity('posts') postsSchema.define({ - // author: profileSchema, - // comments: [commentsSchema] + author: profileSchema, + comments: [commentsSchema] }) commentsSchema.define({ - // postId: postsSchema + postId: postsSchema }) export { From 7771d5bc57c18bbf29ff0e6160eceb2c7610fe83 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 27 Jan 2018 13:16:09 +0300 Subject: [PATCH 4/7] # v0.1.5 process --- CHANGELOG.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fd8ceb..1610333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,16 +10,6 @@ Add new badges # 0.1.4 -# 0.1.5 -Change selector payload type of data, now it's *Immutable JSON or unndefined* please see [test-source](https://github.com/edtoken/redux-tide/blob/master/test/selector.spec.js#L48) -Implement `action.delete` functionality, for details please see [source](https://github.com/edtoken/redux-tide/blob/master/src/action.js#L464) and [example](https://edtoken.github.io/redux-tide/?ex=delete-entity-from-state) and [example-source](https://github.com/edtoken/redux-tide/blob/master/website/src/delete-entity-from-state/index.js#L1) -Improve documentation -Improve examples, add new example -Add code sandbox examples -Add new badges - -# 0.1.4 - # 0.1.3 Fix critical bug in method `Action.empty` small refactoring action.js, selector.js files From e4f60a3b5381cbd6816ade401e82a42987252214 Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 29 Jan 2018 00:14:56 +0300 Subject: [PATCH 5/7] # v0.1.5 process --- CHANGELOG.md | 4 +- README.md | 1 + lib/action.js | 39 ++++++++--------- lib/config.js | 4 +- lib/reducer.js | 20 +++------ lib/selector.js | 1 + src/action.js | 43 ++++++++++--------- src/config.js | 4 +- src/reducer.js | 23 ++++------ src/selector.js | 1 + website/src/App.js | 6 +-- website/src/blog/index.js | 13 +++--- website/src/different-entity-id/index.js | 2 +- website/src/merged-actions-data/index.js | 2 +- .../actions.js | 0 .../index.js | 10 ++--- .../reducer.js | 0 .../schema.js | 0 .../store.js | 0 19 files changed, 81 insertions(+), 92 deletions(-) rename website/src/{delete-entity-from-state => remove-entity-from-state}/actions.js (100%) rename website/src/{delete-entity-from-state => remove-entity-from-state}/index.js (91%) rename website/src/{delete-entity-from-state => remove-entity-from-state}/reducer.js (100%) rename website/src/{delete-entity-from-state => remove-entity-from-state}/schema.js (100%) rename website/src/{delete-entity-from-state => remove-entity-from-state}/store.js (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1610333..db7aff7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,9 @@ # 0.1.5 Change selector payload type of data, now it's *Immutable JSON or unndefined* please see [test-source](https://github.com/edtoken/redux-tide/blob/master/test/selector.spec.js#L48) -Implement `action.delete` functionality, for details please see [source](https://github.com/edtoken/redux-tide/blob/master/src/action.js#L464) and [example](https://edtoken.github.io/redux-tide/?ex=delete-entity-from-state) and [example-source](https://github.com/edtoken/redux-tide/blob/master/website/src/delete-entity-from-state/index.js#L1) +Add query builder result to action store and selector response `args` +Implement `action.remove` +Implement `action.recall` Improve documentation Improve examples, add new example Add code sandbox examples diff --git a/README.md b/README.md index 1e9a352..31da44e 100644 --- a/README.md +++ b/README.md @@ -326,6 +326,7 @@ import {getActionData} from 'redux-tide'; ``` {String} actionId - your action id {*} sourceResult - your source response from server (not mapped response) +{*} args - your args from query builder action method {String} status - pending|success|error {Number} time - timestamp of action {Boolean} hasError - has error or not diff --git a/lib/action.js b/lib/action.js index 7ff5de8..392a602 100644 --- a/lib/action.js +++ b/lib/action.js @@ -69,9 +69,10 @@ var makeActionHandler = function makeActionHandler(Action, actionId, parentActio * * @param {String} error - action error text * @param {Object|Array} payloadSource - response from action result + * @param {Object|Array} args - arguments from queryBuilder * @returns {Object} - action dispatch body */ - return function (error, payloadSource, sourceResult) { + return function (error, payloadSource, sourceResult, args) { if (status === 'success' && payloadSource === undefined) { error = 'Empty payload'; status = 'error'; @@ -121,6 +122,7 @@ var makeActionHandler = function makeActionHandler(Action, actionId, parentActio time: new Date().getTime(), type: '' + actionId, prefix: _config.ACTION_TYPE_PREFIX, + args: args, actionId: actionId, parentActionId: parentActionId, status: status, @@ -139,17 +141,17 @@ var makeActionHandler = function makeActionHandler(Action, actionId, parentActio }; var makeResultCallback = function makeResultCallback(responseMapper, success, error) { - return function (dispatch, getState, err, result) { + return function (dispatch, getState, err, result, args) { try { var errorMessage = (0, _helper.parseError)(err); if (errorMessage) { - return dispatch(error(errorMessage, undefined)); + return dispatch(error(errorMessage, undefined, undefined, args)); } - dispatch(success(undefined, responseMapper(result), result)); + dispatch(success(undefined, responseMapper(result), result, args)); } catch (e) { - dispatch(error(String('' + (e.message || e)), undefined)); + dispatch(error(String('' + (e.message || e)), undefined, undefined, args)); throw e; } }; @@ -183,9 +185,9 @@ var makeCallActionMethod = function makeCallActionMethod(resultCallBack) { if (actionResult instanceof Promise) { return actionResult.then(function (resp) { - return resultCallBack(dispatch, getState, false, resp); + return resultCallBack(dispatch, getState, false, resp, args); }).catch(function (err) { - return resultCallBack(dispatch, getState, err, undefined); + return resultCallBack(dispatch, getState, err, undefined, args); }); } @@ -193,19 +195,19 @@ var makeCallActionMethod = function makeCallActionMethod(resultCallBack) { actionResult = actionResult.call(undefined, dispatch, getState); if (!actionResult) { - return resultCallBack(dispatch, getState, undefined, undefined); + return resultCallBack(dispatch, getState, undefined, undefined, args); } if (actionResult instanceof Promise) { return actionResult.then(function (resp) { - return resultCallBack(dispatch, getState, false, resp); + return resultCallBack(dispatch, getState, false, resp, args); }).catch(function (err) { - return resultCallBack(dispatch, getState, err, undefined); + return resultCallBack(dispatch, getState, err, undefined, args); }); } } - return resultCallBack(dispatch, getState, false, actionResult); + return resultCallBack(dispatch, getState, false, actionResult, args); }; }; @@ -377,7 +379,7 @@ var makeAction = function makeAction(actionId, parentActionId, actionSchema, act * * @returns {Undefined} - returns None, only clear action data */ - this.action.empty = function () { + this.action.reset = function () { return function (dispatch, getState) { dispatch({ time: new Date().getTime(), @@ -390,24 +392,21 @@ var makeAction = function makeAction(actionId, parentActionId, actionSchema, act }; /** - * Delete entity from entity reducer + * Remove action entity id or ids from entities reducer * * @memberOf action.makeAction.Action * @type {Function} * * @example - * store.dispatch(userDeleteAction.delete()) + * store.dispatch(userLoginAction.remove()) * - * @example - * store.dispatch(userDeleteAction.withPrefix(userId).delete()) - * - * @returns {Undefined} - returns None, only delete entity data + * @returns {Undefined} - returns None, only remove entity items */ - this.action.delete = function () { + this.action.remove = function () { return function (dispatch, getState) { dispatch({ time: new Date().getTime(), - type: _config.ACTION_DELETE_TYPE_NAME, + type: _config.ACTION_REMOVE_TYPE_NAME, prefix: _config.ACTION_TYPE_PREFIX, actionId: _this.actionId, actionSchema: _this.schema diff --git a/lib/config.js b/lib/config.js index de498ed..6193587 100644 --- a/lib/config.js +++ b/lib/config.js @@ -77,13 +77,13 @@ var ENTITIES_REDUCER_NAME = exports.ENTITIES_REDUCER_NAME = ACTION_TYPE_PREFIX + var ACTION_EMPTY_TYPE_NAME = exports.ACTION_EMPTY_TYPE_NAME = ACTION_TYPE_PREFIX + '-empty'; /** - * Action type name for clear entity data from entity reducer + * Action type name for delete entities from state * * @memberOf config * @const * @type {String} */ -var ACTION_DELETE_TYPE_NAME = exports.ACTION_DELETE_TYPE_NAME = ACTION_TYPE_PREFIX + '-clean'; +var ACTION_REMOVE_TYPE_NAME = exports.ACTION_REMOVE_TYPE_NAME = ACTION_TYPE_PREFIX + '-remove'; /** * replaced default response mapper to callback diff --git a/lib/reducer.js b/lib/reducer.js index 04c33da..b42df68 100644 --- a/lib/reducer.js +++ b/lib/reducer.js @@ -37,7 +37,8 @@ var makeActionsReducer = function makeActionsReducer(defaultActionsState) { return state; } - var status = action.status, + var args = action.args, + status = action.status, time = action.time, actionId = action.actionId, payload = action.payload, @@ -52,8 +53,8 @@ var makeActionsReducer = function makeActionsReducer(defaultActionsState) { var entityKey = actionSchema.key; - // action.clear - if (action.type === _config.ACTION_EMPTY_TYPE_NAME) { + // action.clear || action.remove + if (action.type === _config.ACTION_EMPTY_TYPE_NAME || action.type === _config.ACTION_REMOVE_TYPE_NAME) { return state.set(actionId, (0, _immutable.fromJS)(Object.assign({ entityKey: entityKey }, actionDefaultData, { time: time }))); } @@ -67,13 +68,8 @@ var makeActionsReducer = function makeActionsReducer(defaultActionsState) { actionState = state.get(actionId); } - // delete entity id from actions - if (action.type === _config.ACTION_DELETE_TYPE_NAME) { - console.log('action delete', actionState); - return state; - } - actionState = actionState.merge({ + args: args, status: status, time: time, hasError: hasError, @@ -127,12 +123,6 @@ var makeEntitiesReducer = function makeEntitiesReducer(defaultEntitiesState) { var newEntitiesItems = normalizedPayloadSource ? normalizedPayloadSource.entities : {}; - // delete entity id from actions - if (action.type === _config.ACTION_DELETE_TYPE_NAME) { - console.log('reducer delete'); - return state; - } - // merge entity item data for (var entityName in newEntitiesItems) { for (var entityId in newEntitiesItems[entityName]) { diff --git a/lib/selector.js b/lib/selector.js index 312f85b..e24cbc3 100644 --- a/lib/selector.js +++ b/lib/selector.js @@ -95,6 +95,7 @@ var _makeGetActionData = function _makeGetActionData(action, actionId, entityNam return Object.assign(makeDefaultActionData(), { actionId: actionId, + args: actionState.get('args'), sourceResult: actionState.get('sourceResult'), status: actionState.get('status'), time: actionState.get('time'), diff --git a/src/action.js b/src/action.js index 54540fd..9b93228 100644 --- a/src/action.js +++ b/src/action.js @@ -3,7 +3,7 @@ */ import { - ACTION_DELETE_TYPE_NAME, + ACTION_REMOVE_TYPE_NAME, ACTION_EMPTY_TYPE_NAME, ACTION_ID_KEY, ACTION_IDS_KEY, @@ -81,9 +81,10 @@ const makeActionHandler = ( * * @param {String} error - action error text * @param {Object|Array} payloadSource - response from action result + * @param {Object|Array} args - arguments from queryBuilder * @returns {Object} - action dispatch body */ - return function(error, payloadSource, sourceResult) { + return function(error, payloadSource, sourceResult, args) { if (status === 'success' && payloadSource === undefined) { error = 'Empty payload' status = 'error' @@ -143,6 +144,7 @@ const makeActionHandler = ( time: new Date().getTime(), type: `${actionId}`, prefix: ACTION_TYPE_PREFIX, + args, actionId, parentActionId, status, @@ -161,17 +163,17 @@ const makeActionHandler = ( } const makeResultCallback = (responseMapper, success, error) => { - return function(dispatch, getState, err, result) { + return function(dispatch, getState, err, result, args) { try { const errorMessage = parseError(err) if (errorMessage) { - return dispatch(error(errorMessage, undefined)) + return dispatch(error(errorMessage, undefined, undefined, args)) } - dispatch(success(undefined, responseMapper(result), result)) + dispatch(success(undefined, responseMapper(result), result, args)) } catch (e) { - dispatch(error(String(`${e.message || e}`), undefined)) + dispatch(error(String(`${e.message || e}`), undefined, undefined, args)) throw e } } @@ -208,25 +210,27 @@ const makeCallActionMethod = resultCallBack => { if (actionResult instanceof Promise) { return actionResult - .then(resp => resultCallBack(dispatch, getState, false, resp)) - .catch(err => resultCallBack(dispatch, getState, err, undefined)) + .then(resp => resultCallBack(dispatch, getState, false, resp, args)) + .catch(err => resultCallBack(dispatch, getState, err, undefined, args)) } if (typeof actionResult === 'function') { actionResult = actionResult.call(this, dispatch, getState) if (!actionResult) { - return resultCallBack(dispatch, getState, undefined, undefined) + return resultCallBack(dispatch, getState, undefined, undefined, args) } if (actionResult instanceof Promise) { return actionResult - .then(resp => resultCallBack(dispatch, getState, false, resp)) - .catch(err => resultCallBack(dispatch, getState, err, undefined)) + .then(resp => resultCallBack(dispatch, getState, false, resp, args)) + .catch(err => + resultCallBack(dispatch, getState, err, undefined, args) + ) } } - return resultCallBack(dispatch, getState, false, actionResult) + return resultCallBack(dispatch, getState, false, actionResult, args) } } @@ -435,7 +439,7 @@ const makeAction = function( * * @returns {Undefined} - returns None, only clear action data */ - this.action.empty = () => { + this.action.reset = () => { return (dispatch, getState) => { dispatch({ time: new Date().getTime(), @@ -448,24 +452,21 @@ const makeAction = function( } /** - * Delete entity from entity reducer + * Remove action entity id or ids from entities reducer * * @memberOf action.makeAction.Action * @type {Function} * * @example - * store.dispatch(userDeleteAction.delete()) + * store.dispatch(userLoginAction.remove()) * - * @example - * store.dispatch(userDeleteAction.withPrefix(userId).delete()) - * - * @returns {Undefined} - returns None, only delete entity data + * @returns {Undefined} - returns None, only remove entity items */ - this.action.delete = () => { + this.action.remove = () => { return (dispatch, getState) => { dispatch({ time: new Date().getTime(), - type: ACTION_DELETE_TYPE_NAME, + type: ACTION_REMOVE_TYPE_NAME, prefix: ACTION_TYPE_PREFIX, actionId: this.actionId, actionSchema: this.schema diff --git a/src/config.js b/src/config.js index 942f9c5..f7b1681 100644 --- a/src/config.js +++ b/src/config.js @@ -72,13 +72,13 @@ export const ENTITIES_REDUCER_NAME = `${ACTION_TYPE_PREFIX}-entities` export const ACTION_EMPTY_TYPE_NAME = `${ACTION_TYPE_PREFIX}-empty` /** - * Action type name for clear entity data from entity reducer + * Action type name for delete entities from state * * @memberOf config * @const * @type {String} */ -export const ACTION_DELETE_TYPE_NAME = `${ACTION_TYPE_PREFIX}-clean` +export const ACTION_REMOVE_TYPE_NAME = `${ACTION_TYPE_PREFIX}-remove` /** * replaced default response mapper to callback diff --git a/src/reducer.js b/src/reducer.js index ed21c27..43b11d7 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -6,8 +6,8 @@ import { fromJS } from 'immutable' import { normalize } from 'normalizr' import { - ACTION_DELETE_TYPE_NAME, ACTION_EMPTY_TYPE_NAME, + ACTION_REMOVE_TYPE_NAME, ACTION_TYPE_PREFIX, ACTIONS_REDUCER_NAME, ENTITIES_REDUCER_NAME @@ -33,6 +33,7 @@ const makeActionsReducer = defaultActionsState => { } const { + args, status, time, actionId, @@ -48,8 +49,11 @@ const makeActionsReducer = defaultActionsState => { const entityKey = actionSchema.key - // action.clear - if (action.type === ACTION_EMPTY_TYPE_NAME) { + // action.clear || action.remove + if ( + action.type === ACTION_EMPTY_TYPE_NAME || + action.type === ACTION_REMOVE_TYPE_NAME + ) { return state.set( actionId, fromJS(Object.assign({ entityKey }, actionDefaultData, { time })) @@ -68,13 +72,8 @@ const makeActionsReducer = defaultActionsState => { actionState = state.get(actionId) } - // delete entity id from actions - if (action.type === ACTION_DELETE_TYPE_NAME) { - console.log('action delete', actionState) - return state - } - actionState = actionState.merge({ + args, status, time, hasError, @@ -143,12 +142,6 @@ const makeEntitiesReducer = defaultEntitiesState => { ? normalizedPayloadSource.entities : {} - // delete entity id from actions - if (action.type === ACTION_DELETE_TYPE_NAME) { - console.log('reducer delete') - return state - } - // merge entity item data for (let entityName in newEntitiesItems) { for (let entityId in newEntitiesItems[entityName]) { diff --git a/src/selector.js b/src/selector.js index 1d181b5..85fc89a 100644 --- a/src/selector.js +++ b/src/selector.js @@ -124,6 +124,7 @@ const _makeGetActionData = (action, actionId, entityName, actionSchema) => { makeDefaultActionData(), { actionId, + args: actionState.get('args'), sourceResult: actionState.get('sourceResult'), status: actionState.get('status'), time: actionState.get('time'), diff --git a/website/src/App.js b/website/src/App.js index 4bac8a4..ea0213c 100644 --- a/website/src/App.js +++ b/website/src/App.js @@ -25,9 +25,9 @@ const EXAMPLES = [ 'component': require('./merged-actions-data') }, { - 'title': 'Delete entity from state', - 'path': 'delete-entity-from-state', - 'component': require('./delete-entity-from-state') + 'title': 'Remove entity from state', + 'path': 'remove-entity-from-state', + 'component': require('./remove-entity-from-state') } ] diff --git a/website/src/blog/index.js b/website/src/blog/index.js index c257a53..8d1be18 100644 --- a/website/src/blog/index.js +++ b/website/src/blog/index.js @@ -62,12 +62,13 @@ class BlogPostFormComponent extends Component { } render() { - const {isFetching, hasError, errorText, payload} = this.props + const {isFetching, hasError, errorText, payload, args} = this.props const {saved, form} = this.state const disableEdit = isFetching const completed = saved && this.props.status === 'success' - console.log('payload', payload) + // console.log('args', args) + // console.log('payload', payload) return (
@@ -108,6 +109,7 @@ class BlogPostFormComponent extends Component { (this._handleChange(e))} @@ -127,7 +129,8 @@ class BlogPostFormComponent extends Component {

fetchPost payload:

-
{JSON.stringify(payload, null, 2)}
+ {payload &&
{JSON.stringify({...payload.toJS(), comments: ['... Comments List ...']}, null, 2)}
} +
@@ -289,8 +292,8 @@ class BlogExampleComponent extends Component {

Blog Example

Preview in SandBox codesandbox.io + href='https://codesandbox.io/s/github/edtoken/redux-tide/tree/master/website?module=/src/blog/index.js&moduleview=1' + target='_blank'>codesandbox.io

Source code 
{hasError &&

} -
{JSON.stringify(payload, null, 2)}
+ {payload &&
{JSON.stringify({...payload.toJS(), comments: ['... Comments List ...']}, null, 2)}
}
) } } diff --git a/website/src/merged-actions-data/index.js b/website/src/merged-actions-data/index.js index 0f5c546..af4d388 100644 --- a/website/src/merged-actions-data/index.js +++ b/website/src/merged-actions-data/index.js @@ -41,7 +41,7 @@ class CommonPostComponent extends Component {

{hasError &&
{errorText}
} -
{JSON.stringify(payload, null, 2)}
+ {payload &&
{JSON.stringify({...payload.toJS(), comments: ['... Comments List ...']}, null, 2)}
}
) } } diff --git a/website/src/delete-entity-from-state/actions.js b/website/src/remove-entity-from-state/actions.js similarity index 100% rename from website/src/delete-entity-from-state/actions.js rename to website/src/remove-entity-from-state/actions.js diff --git a/website/src/delete-entity-from-state/index.js b/website/src/remove-entity-from-state/index.js similarity index 91% rename from website/src/delete-entity-from-state/index.js rename to website/src/remove-entity-from-state/index.js index 128733a..c37c15b 100644 --- a/website/src/delete-entity-from-state/index.js +++ b/website/src/remove-entity-from-state/index.js @@ -78,14 +78,10 @@ const CommonPost = connect( class DeleteTntityFromStateExampleComponent extends Component { - constructor(props) { - super(props) - } - render() { return (
-

Delete Entity from state

+

Remove Entity from state

Preview in SandBox  - Demonstrate how to use `dispatch(action.delete())` method
+ Demonstrate how to use `dispatch(action.remove())` method
+ When you do `DELETE users/:user_id`, you need to delete entity from normalized store
+ For this, you can use `dispatch(deleteUserAction.remove())` or `dispatch(deleteUserAction.withPrefix(userId).remove())`

diff --git a/website/src/delete-entity-from-state/reducer.js b/website/src/remove-entity-from-state/reducer.js similarity index 100% rename from website/src/delete-entity-from-state/reducer.js rename to website/src/remove-entity-from-state/reducer.js diff --git a/website/src/delete-entity-from-state/schema.js b/website/src/remove-entity-from-state/schema.js similarity index 100% rename from website/src/delete-entity-from-state/schema.js rename to website/src/remove-entity-from-state/schema.js diff --git a/website/src/delete-entity-from-state/store.js b/website/src/remove-entity-from-state/store.js similarity index 100% rename from website/src/delete-entity-from-state/store.js rename to website/src/remove-entity-from-state/store.js From c48af7087864a8e3d882c6a24e9ed724059f7f67 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 11 Feb 2018 18:35:46 +0300 Subject: [PATCH 6/7] remove object.freeze from action body --- README.md | 12 +++++++++++- src/action.js | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31da44e..0a72e9d 100644 --- a/README.md +++ b/README.md @@ -229,12 +229,22 @@ export const createNewPost = createAction( ] ) +export const getPostById = createAction( + postsSchema, + get, + (postId) => { + return (dispatch, getState)=>{ + // return Promise (axios call or other) + } + } +) + // basic redux action can be use export const openEditPost = (postId) => { return { type:OPEN_EDIT, postId - } + } } ``` diff --git a/src/action.js b/src/action.js index 9b93228..74730c6 100644 --- a/src/action.js +++ b/src/action.js @@ -140,7 +140,7 @@ const makeActionHandler = ( * payloadSource: Object|Array * }} */ - return Object.freeze({ + return { time: new Date().getTime(), type: `${actionId}`, prefix: ACTION_TYPE_PREFIX, @@ -158,7 +158,7 @@ const makeActionHandler = ( sourceResult, payload, payloadSource - }) + } } } From 7354aacb035f3826dd7d754e3e67eed51161dbb1 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 11 Feb 2018 21:14:14 +0300 Subject: [PATCH 7/7] remove object.freeze from action body --- lib/action.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/action.js b/lib/action.js index 392a602..06f0a33 100644 --- a/lib/action.js +++ b/lib/action.js @@ -118,7 +118,7 @@ var makeActionHandler = function makeActionHandler(Action, actionId, parentActio * payloadSource: Object|Array * }} */ - return Object.freeze({ + return { time: new Date().getTime(), type: '' + actionId, prefix: _config.ACTION_TYPE_PREFIX, @@ -136,7 +136,7 @@ var makeActionHandler = function makeActionHandler(Action, actionId, parentActio sourceResult: sourceResult, payload: payload, payloadSource: payloadSource - }); + }; }; };