refactor local storage to use a component

This commit is contained in:
Adam Brown 2016-12-15 14:28:23 -05:00
parent 6bb76ccd17
commit 720f123977
4 changed files with 104 additions and 53 deletions

View File

@ -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<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if("value"in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};}();var _react=__webpack_require__(0);var _react2=_interopRequireDefault(_react);var _reactRedux=__webpack_require__(69);var _actions=__webpack_require__(70);var Actions=_interopRequireWildcard(_actions);var _selectors=__webpack_require__(196);var Selectors=_interopRequireWildcard(_selectors);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};}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _possibleConstructorReturn(self,call){if(!self){throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return call&&(typeof call==="object"||typeof call==="function")?call:self;}function _inherits(subClass,superClass){if(typeof superClass!=="function"&&superClass!==null){throw new TypeError("Super expression must either be null or a function, not "+typeof superClass);}subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,enumerable:false,writable:true,configurable:true}});if(superClass)Object.setPrototypeOf?Object.setPrototypeOf(subClass,superClass):subClass.__proto__=superClass;}/* This component reads the local storage store and adds them to the Redux store.
* Local storage is read during the componentDidMount lifecycle method.
* Local storage is written during the componentWillReceiveProps lifecycle method.
*///an app-specific name for the localStorage state
var stateName="dubdiff_state";//return a new object with the given keys, each assigned to the cooresponding value
//from the given object
var copyKeys=function copyKeys(obj,keys){return keys.reduce(function(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)){var 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){var toSave=copyKeys(state,keys);localStorage.setItem(stateName,JSON.stringify(toSave));}var mapStateToProps=function mapStateToProps(state){return{input:state.input};};var mapDispatchToProps=function mapDispatchToProps(dispatch){return{onChangeOriginal:function onChangeOriginal(text){return dispatch(Actions.updateOriginalInput(text));},onChangeFinal:function onChangeFinal(text){return dispatch(Actions.updateFinalInput(text));}};};var LocalStorage=function(_React$Component){_inherits(LocalStorage,_React$Component);function LocalStorage(){_classCallCheck(this,LocalStorage);return _possibleConstructorReturn(this,(LocalStorage.__proto__||Object.getPrototypeOf(LocalStorage)).apply(this,arguments));}_createClass(LocalStorage,[{key:'componentDidMount',//load the state from the local storage
value:function componentDidMount(){//only if the status is EMPTY
if(this.props.input.original==''&&this.props.input.final==''){var 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
},{key:'componentWillReceiveProps',value:function componentWillReceiveProps(nextProps){setLocalState(nextProps,['input']);}},{key:'render',value:function render(){return this.props.children;}}]);return LocalStorage;}(_react2.default.Component);exports.default=(0,_reactRedux.connect)(mapStateToProps,mapDispatchToProps)(LocalStorage);
/***/ }
/******/ ]);

View File

@ -0,0 +1,77 @@
import React from 'react'
import {connect} from 'react-redux'
import * as Actions from '../common/actions'
import * as Selectors from '../common/selectors'
/* This component reads the local storage store and adds them to the Redux store.
* Local storage is read during the componentDidMount lifecycle method.
* Local storage is written during the componentWillReceiveProps lifecycle method.
*/
//an app-specific name for the localStorage state
const stateName = "dubdiff_state"
//return a new object with the given keys, each assigned to the cooresponding value
//from the given object
const copyKeys = (obj, keys) => 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)

View File

@ -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(
<Provider store={store}>
<LocalStorage >
<Router history={browserHistory}>
{routes}
</Router>
</LocalStorage>
</Provider>
, document.getElementById('root'))
}

View File

@ -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))
}