From 720f1239771fe29000ed0ef548f7d8772ee2f725 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 15 Dec 2016 14:28:23 -0500 Subject: [PATCH] refactor local storage to use a component --- dist/browser-bundle.js | 43 +++++++++++---------- src/client/LocalStorage.js | 77 ++++++++++++++++++++++++++++++++++++++ src/client/index.js | 27 +++---------- src/common/localStore.js | 10 ----- 4 files changed, 104 insertions(+), 53 deletions(-) create mode 100644 src/client/LocalStorage.js delete mode 100644 src/common/localStore.js diff --git a/dist/browser-bundle.js b/dist/browser-bundle.js index c87aec5..456836b 100644 --- a/dist/browser-bundle.js +++ b/dist/browser-bundle.js @@ -9873,13 +9873,7 @@ function(acc,x,i){return test(x)?acc.concat([i]):acc;},//start with the empty ar 'use strict';exports.__esModule=true;function createThunkMiddleware(extraArgument){return function(_ref){var dispatch=_ref.dispatch;var getState=_ref.getState;return function(next){return function(action){if(typeof action==='function'){return action(dispatch,getState,extraArgument);}return next(action);};};};}var thunk=createThunkMiddleware();thunk.withExtraArgument=createThunkMiddleware;exports['default']=thunk; /***/ }, -/* 573 */ -/***/ function(module, exports) { - -"use strict"; -"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.set=set;var stateName=function stateName(suffix){return'state'+(suffix?suffix:"");};var get=exports.get=function get(suffix){return JSON.parse(localStorage.getItem(stateName(suffix)))||undefined;};function set(state,props,suffix){var toSave={};props.forEach(function(p){return toSave[p]=state[p];});localStorage.setItem(stateName(suffix),JSON.stringify(toSave));} - -/***/ }, +/* 573 */, /* 574 */ /***/ function(module, exports, __webpack_require__) { @@ -23332,7 +23326,7 @@ module.exports = [ /***/ function(module, exports, __webpack_require__) { "use strict"; -'use strict';var _react=__webpack_require__(0);var _react2=_interopRequireDefault(_react);var _reactDom=__webpack_require__(303);var _reactDom2=_interopRequireDefault(_reactDom);var _redux=__webpack_require__(304);var Redux=_interopRequireWildcard(_redux);var _reactRedux=__webpack_require__(69);var _reactRouter=__webpack_require__(84);var _reduxThunk=__webpack_require__(572);var _reduxThunk2=_interopRequireDefault(_reduxThunk);var _localStore=__webpack_require__(573);var localStore=_interopRequireWildcard(_localStore);var _reducers=__webpack_require__(574);var reducers=_interopRequireWildcard(_reducers);var _routes=__webpack_require__(575);var _routes2=_interopRequireDefault(_routes);var _actions=__webpack_require__(70);var Actions=_interopRequireWildcard(_actions);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}//the localStore implementation is naive +'use strict';var _react=__webpack_require__(0);var _react2=_interopRequireDefault(_react);var _reactDom=__webpack_require__(303);var _reactDom2=_interopRequireDefault(_reactDom);var _redux=__webpack_require__(304);var Redux=_interopRequireWildcard(_redux);var _reactRedux=__webpack_require__(69);var _reactRouter=__webpack_require__(84);var _reduxThunk=__webpack_require__(572);var _reduxThunk2=_interopRequireDefault(_reduxThunk);var _reducers=__webpack_require__(574);var reducers=_interopRequireWildcard(_reducers);var _routes=__webpack_require__(575);var _routes2=_interopRequireDefault(_routes);var _actions=__webpack_require__(70);var Actions=_interopRequireWildcard(_actions);var _LocalStorage=__webpack_require__(1216);var _LocalStorage2=_interopRequireDefault(_LocalStorage);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}//the localStore implementation is naive //initial state should be rehydrated from the server //then additional state transformations should be applied based on localStore contents // (or not? maybe localStore is not needed) @@ -23340,20 +23334,7 @@ module.exports = [ var initialState=window.__INITIAL_STATE__;//create the list of middlewares var middlewares=[_reduxThunk2.default];//create the redux store //initial state is retrieved from localStore -var store=Redux.createStore(Redux.combineReducers(reducers),initialState,window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__(Redux.applyMiddleware.apply(Redux,middlewares)):Redux.applyMiddleware.apply(Redux,middlewares));//this way of reading local input isn't working: -// it's just overriding what comes from the server -// and it's not respecting the comparison that is loaded from the server -/* -const localInput = localStore.get('dubdiff') -if (localInput.input) { - //dispatch localStore data to store - store.dispatch(Actions.updateOriginalInput(localInput.input.original)) - store.dispatch(Actions.updateFinalInput(localInput.input.final)) - //should this be done after the first render? -} -*///save the state whenever the state changes -function saveState(){var state=store.getState();//pass the elements of state that should be persisted to the local store as an array of element name strings -localStore.set(state,["input"],"dubdiff");}store.subscribe(saveState);function render(){_reactDom2.default.render(_react2.default.createElement(_reactRedux.Provider,{store:store},_react2.default.createElement(_reactRouter.Router,{history:_reactRouter.browserHistory},_routes2.default)),document.getElementById('root'));}render(); +var store=Redux.createStore(Redux.combineReducers(reducers),initialState,window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__(Redux.applyMiddleware.apply(Redux,middlewares)):Redux.applyMiddleware.apply(Redux,middlewares));function render(){_reactDom2.default.render(_react2.default.createElement(_reactRedux.Provider,{store:store},_react2.default.createElement(_LocalStorage2.default,null,_react2.default.createElement(_reactRouter.Router,{history:_reactRouter.browserHistory},_routes2.default))),document.getElementById('root'));}render(); /***/ }, /* 1214 */ @@ -23376,5 +23357,23 @@ function iteratorFor(items){var iterator={next:function next(){var value=items.s this._bodyInit=new Blob([this._bodyArrayBuffer]);}else if(support.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(body)||isArrayBufferView(body))){this._bodyArrayBuffer=bufferClone(body);}else{throw new Error('unsupported BodyInit type');}if(!this.headers.get('content-type')){if(typeof body==='string'){this.headers.set('content-type','text/plain;charset=UTF-8');}else if(this._bodyBlob&&this._bodyBlob.type){this.headers.set('content-type',this._bodyBlob.type);}else if(support.searchParams&&URLSearchParams.prototype.isPrototypeOf(body)){this.headers.set('content-type','application/x-www-form-urlencoded;charset=UTF-8');}}};if(support.blob){this.blob=function(){var rejected=consumed(this);if(rejected){return rejected;}if(this._bodyBlob){return Promise.resolve(this._bodyBlob);}else if(this._bodyArrayBuffer){return Promise.resolve(new Blob([this._bodyArrayBuffer]));}else if(this._bodyFormData){throw new Error('could not read FormData body as blob');}else{return Promise.resolve(new Blob([this._bodyText]));}};this.arrayBuffer=function(){if(this._bodyArrayBuffer){return consumed(this)||Promise.resolve(this._bodyArrayBuffer);}else{return this.blob().then(readBlobAsArrayBuffer);}};}this.text=function(){var rejected=consumed(this);if(rejected){return rejected;}if(this._bodyBlob){return readBlobAsText(this._bodyBlob);}else if(this._bodyArrayBuffer){return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));}else if(this._bodyFormData){throw new Error('could not read FormData body as text');}else{return Promise.resolve(this._bodyText);}};if(support.formData){this.formData=function(){return this.text().then(decode);};}this.json=function(){return this.text().then(JSON.parse);};return this;}// HTTP methods whose capitalization should be normalized var methods=['DELETE','GET','HEAD','OPTIONS','POST','PUT'];function normalizeMethod(method){var upcased=method.toUpperCase();return methods.indexOf(upcased)>-1?upcased:method;}function Request(input,options){options=options||{};var body=options.body;if(typeof input==='string'){this.url=input;}else{if(input.bodyUsed){throw new TypeError('Already read');}this.url=input.url;this.credentials=input.credentials;if(!options.headers){this.headers=new Headers(input.headers);}this.method=input.method;this.mode=input.mode;if(!body&&input._bodyInit!=null){body=input._bodyInit;input.bodyUsed=true;}}this.credentials=options.credentials||this.credentials||'omit';if(options.headers||!this.headers){this.headers=new Headers(options.headers);}this.method=normalizeMethod(options.method||this.method||'GET');this.mode=options.mode||this.mode||null;this.referrer=null;if((this.method==='GET'||this.method==='HEAD')&&body){throw new TypeError('Body not allowed for GET or HEAD requests');}this._initBody(body);}Request.prototype.clone=function(){return new Request(this,{body:this._bodyInit});};function decode(body){var form=new FormData();body.trim().split('&').forEach(function(bytes){if(bytes){var split=bytes.split('=');var name=split.shift().replace(/\+/g,' ');var value=split.join('=').replace(/\+/g,' ');form.append(decodeURIComponent(name),decodeURIComponent(value));}});return form;}function parseHeaders(rawHeaders){var headers=new Headers();rawHeaders.split('\r\n').forEach(function(line){var parts=line.split(':');var key=parts.shift().trim();if(key){var value=parts.join(':').trim();headers.append(key,value);}});return headers;}Body.call(Request.prototype);function Response(bodyInit,options){if(!options){options={};}this.type='default';this.status='status'in options?options.status:200;this.ok=this.status>=200&&this.status<300;this.statusText='statusText'in options?options.statusText:'OK';this.headers=new Headers(options.headers);this.url=options.url||'';this._initBody(bodyInit);}Body.call(Response.prototype);Response.prototype.clone=function(){return new Response(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new Headers(this.headers),url:this.url});};Response.error=function(){var response=new Response(null,{status:0,statusText:''});response.type='error';return response;};var redirectStatuses=[301,302,303,307,308];Response.redirect=function(url,status){if(redirectStatuses.indexOf(status)===-1){throw new RangeError('Invalid status code');}return new Response(null,{status:status,headers:{location:url}});};self.Headers=Headers;self.Request=Request;self.Response=Response;self.fetch=function(input,init){return new Promise(function(resolve,reject){var request=new Request(input,init);var xhr=new XMLHttpRequest();xhr.onload=function(){var options={status:xhr.status,statusText:xhr.statusText,headers:parseHeaders(xhr.getAllResponseHeaders()||'')};options.url='responseURL'in xhr?xhr.responseURL:options.headers.get('X-Request-URL');var body='response'in xhr?xhr.response:xhr.responseText;resolve(new Response(body,options));};xhr.onerror=function(){reject(new TypeError('Network request failed'));};xhr.ontimeout=function(){reject(new TypeError('Network request failed'));};xhr.open(request.method,request.url,true);if(request.credentials==='include'){xhr.withCredentials=true;}if('responseType'in xhr&&support.blob){xhr.responseType='blob';}request.headers.forEach(function(value,name){xhr.setRequestHeader(name,value);});xhr.send(typeof request._bodyInit==='undefined'?null:request._bodyInit);});};self.fetch.polyfill=true;})(typeof self!=='undefined'?self:undefined); +/***/ }, +/* 1216 */ +/***/ function(module, exports, __webpack_require__) { + +"use strict"; +'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i keys.reduce((acc, p)=>{acc[p]=obj[p]; return acc}, {}) + +console.log(copyKeys({a:1, b:2}, ['a'])) +console.log(copyKeys({}, ['a'])) + +//utility method for retrieving json data from the local store +function getLocalState (keys) { + if (localStorage.getItem(stateName)) { + const localState = JSON.parse(localStorage.getItem(stateName)) + return copyKeys(localState, keys) + } + else + return copyKeys({}, keys) +} + +//utility method for writing json data to the local store +function setLocalState (state, keys) { + let toSave = copyKeys(state, keys) + localStorage.setItem(stateName, JSON.stringify(toSave)) +} + + +const mapStateToProps = (state) => ({ + input: state.input, + //the loading/empty/clean state +}) + + +const mapDispatchToProps = dispatch => ({ + onChangeOriginal: (text) => dispatch(Actions.updateOriginalInput(text)), + onChangeFinal: (text) => dispatch(Actions.updateFinalInput(text)), +}) + + +class LocalStorage extends React.Component { + + //load the state from the local storage + componentDidMount() { + //only if the status is EMPTY + if (this.props.input.original=='' && this.props.input.final == '') { + const localState = getLocalState(['input']) + if (localState.input && localState.input.original) + this.props.onChangeOriginal(localState.input.original) + if (localState.input && localState.input.final) + this.props.onChangeFinal(localState.input.final) + } + } + //save the state to local storage + componentWillReceiveProps(nextProps) { + setLocalState(nextProps, ['input']) + } + + render () { + return this.props.children + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(LocalStorage) + diff --git a/src/client/index.js b/src/client/index.js index 8a20e89..537d66c 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -10,10 +10,11 @@ import {Router, Route, IndexRoute, Redirect, browserHistory } from 'react-route import thunk from 'redux-thunk' -import * as localStore from '../common/localStore' import * as reducers from '../common/reducers' import routes from '../common/routes' -import * as Actions from '../common/actions' +import * as Actions from '../common/actions' + +import LocalStorage from './LocalStorage' @@ -38,35 +39,19 @@ const store = Redux.createStore( Redux.applyMiddleware(...middlewares) ) -//this way of reading local input isn't working: -// it's just overriding what comes from the server -// and it's not respecting the comparison that is loaded from the server -/* -const localInput = localStore.get('dubdiff') -if (localInput.input) { - //dispatch localStore data to store - store.dispatch(Actions.updateOriginalInput(localInput.input.original)) - store.dispatch(Actions.updateFinalInput(localInput.input.final)) - //should this be done after the first render? -} -*/ -//save the state whenever the state changes -function saveState() { - let state = store.getState() - //pass the elements of state that should be persisted to the local store as an array of element name strings - localStore.set(state, ["input"], "dubdiff") -} -store.subscribe(saveState) + function render() { ReactDOM.render( + {routes} + , document.getElementById('root')) } diff --git a/src/common/localStore.js b/src/common/localStore.js deleted file mode 100644 index 354e6fe..0000000 --- a/src/common/localStore.js +++ /dev/null @@ -1,10 +0,0 @@ -let stateName = (suffix) => 'state'+(suffix?suffix:"") - -export const get = (suffix) => JSON.parse(localStorage.getItem(stateName(suffix))) || undefined; - -export function set (state, props, suffix) { - let toSave = {} - props.forEach(p => toSave[p] = state[p]) - localStorage.setItem(stateName(suffix), JSON.stringify(toSave)) -} -