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() + }) } }