Split config rehydration off into a different file for store

This commit is contained in:
HenryNguyen5 2018-02-02 17:19:39 -05:00
parent 74e3cce1d8
commit b39b36d0dc
3 changed files with 167 additions and 61 deletions

View File

@ -0,0 +1,156 @@
import { State as ConfigState, config } from 'reducers/config';
import { dedupeCustomTokens } from 'utils/tokens';
import {
State as CustomTokenState,
INITIAL_STATE as customTokensInitialState
} from 'reducers/customTokens';
import { loadStatePropertyOrEmptyObject } from 'utils/localStorage';
import {
isStaticNodeId,
isStaticNetworkId,
getLanguageSelection,
getCustomNodeConfigs,
getSelectedNode,
getCustomNetworkConfigs,
getSelectedNetwork
} from 'selectors/config';
import RootReducer, { AppState } from 'reducers';
import CustomNode from 'libs/nodes/custom';
import { CustomNodeConfig } from 'types/node';
const appInitialState = RootReducer(undefined as any, { type: 'inital_state' });
type DeepPartial<T> = { [P in keyof T]?: DeepPartial<T[P]> };
export function getConfigAndCustomTokensStateToSubscribe(
state: AppState
): Pick<DeepPartial<AppState>, 'config' | 'customTokens'> {
const subscribedConfig: DeepPartial<ConfigState> = {
meta: { languageSelection: getLanguageSelection(state) },
nodes: { customNodes: getCustomNodeConfigs(state), selectedNode: getSelectedNode(state) },
networks: {
customNetworks: getCustomNetworkConfigs(state),
selectedNetwork: getSelectedNetwork(state)
}
};
const subscribedTokens = state.customTokens;
return { config: subscribedConfig, customTokens: subscribedTokens };
}
export function rehydrateConfigAndCustomTokenState() {
const configInitialState = config(undefined as any, { type: 'inital_state' });
const savedConfigState = loadStatePropertyOrEmptyObject<ConfigState>('config');
const nextConfigState = { ...configInitialState };
// If they have a saved node, make sure we assign that too. The node selected
// isn't serializable, so we have to assign it here.
if (savedConfigState) {
// we assign networks first so that when we re-hydrate custom nodes, we can check that the network exists
nextConfigState.networks = rehydrateNetworks(
configInitialState.networks,
savedConfigState.networks
);
nextConfigState.nodes = rehydrateNodes(
configInitialState.nodes,
savedConfigState.nodes,
nextConfigState.networks
);
nextConfigState.meta = { ...nextConfigState.meta, ...savedConfigState.meta };
}
const nextCustomTokenState = rehydrateCustomTokens(nextConfigState.networks);
return { config: nextConfigState, customTokens: nextCustomTokenState };
}
function rehydrateCustomTokens(networkState: ConfigState['networks']) {
// Dedupe custom tokens initially
const savedCustomTokensState =
loadStatePropertyOrEmptyObject<CustomTokenState>('customTokens') || customTokensInitialState;
const { customNetworks, selectedNetwork, staticNetworks } = networkState;
const network = isStaticNetworkId(appInitialState, selectedNetwork)
? staticNetworks[selectedNetwork]
: customNetworks[selectedNetwork];
return network.isCustom
? savedCustomTokensState
: dedupeCustomTokens(network.tokens, savedCustomTokensState);
}
function rehydrateNetworks(
initialState: ConfigState['networks'],
savedState: ConfigState['networks']
): ConfigState['networks'] {
const nextNetworkState = { ...initialState };
nextNetworkState.customNetworks = savedState.customNetworks;
const { customNetworks, selectedNetwork, staticNetworks } = nextNetworkState;
const nextSelectedNetwork = isStaticNetworkId(appInitialState, savedState.selectedNetwork)
? staticNetworks[selectedNetwork]
: customNetworks[selectedNetwork];
nextNetworkState.selectedNetwork = nextSelectedNetwork
? savedState.selectedNetwork
: initialState.selectedNetwork;
return nextNetworkState;
}
function rehydrateNodes(
initalState: ConfigState['nodes'],
savedState: ConfigState['nodes'],
networkState: ConfigState['networks']
): ConfigState['nodes'] {
const nextNodeState = { ...initalState };
// re-assign the hydrated nodes
nextNodeState.customNodes = rehydrateCustomNodes(savedState.customNodes, networkState);
const { customNodes, staticNodes } = nextNodeState;
nextNodeState.selectedNode = getSavedSelectedNode(
nextNodeState.selectedNode,
savedState.selectedNode,
customNodes,
staticNodes
);
return nextNodeState;
}
function getSavedSelectedNode(
initialState: ConfigState['nodes']['selectedNode'],
savedState: ConfigState['nodes']['selectedNode'],
customNodes: ConfigState['nodes']['customNodes'],
staticNodes: ConfigState['nodes']['staticNodes']
): ConfigState['nodes']['selectedNode'] {
const { nodeId: savedNodeId } = savedState;
// if 'web3' has persisted as node selection, reset to app default
// necessary because web3 is only initialized as a node upon MetaMask / Mist unlock
if (savedNodeId === 'web3') {
return { nodeId: initialState.nodeId, pending: false };
}
const nodeConfigExists = isStaticNodeId(appInitialState, savedNodeId)
? staticNodes[savedNodeId]
: customNodes[savedNodeId];
return { nodeId: nodeConfigExists ? savedNodeId : initialState.nodeId, pending: false };
}
function rehydrateCustomNodes(
state: ConfigState['nodes']['customNodes'],
networkState: ConfigState['networks']
) {
const networkExists = (networkId: string) => Object.keys(networkState).includes(networkId);
const rehydratedCustomNodes = Object.entries(state).reduce(
(hydratedNodes, [customNodeId, configToHydrate]) => {
if (!networkExists(configToHydrate.network)) {
return hydratedNodes;
}
const lib = new CustomNode(configToHydrate);
const hydratedNode: CustomNodeConfig = { ...configToHydrate, lib };
return { ...hydratedNodes, [customNodeId]: hydratedNode };
},
{} as ConfigState['nodes']['customNodes']
);
return rehydratedCustomNodes;
}

1
common/store/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './store';

View File

@ -1,13 +1,5 @@
import throttle from 'lodash/throttle';
import { routerMiddleware } from 'react-router-redux';
/*
import { State as ConfigState, INITIAL_STATE as configInitialState } from 'reducers/config';
*/
import {
State as CustomTokenState,
INITIAL_STATE as customTokensInitialState
} from 'reducers/customTokens';
import {
INITIAL_STATE as transactionInitialState,
State as TransactionState
@ -18,11 +10,14 @@ import { composeWithDevTools } from 'redux-devtools-extension';
import { createLogger } from 'redux-logger';
import createSagaMiddleware from 'redux-saga';
import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage';
import RootReducer from './reducers';
import RootReducer from 'reducers';
import promiseMiddleware from 'redux-promise-middleware';
import { dedupeCustomTokens } from 'utils/tokens';
import sagas from './sagas';
import sagas from 'sagas';
import { gasPricetoBase } from 'libs/units';
import {
rehydrateConfigAndCustomTokenState,
getConfigAndCustomTokensStateToSubscribe
} from './configAndTokens';
const configureStore = () => {
const logger = createLogger({
@ -62,40 +57,8 @@ const configureStore = () => {
: { ...swapInitialState };
const savedTransactionState = loadStatePropertyOrEmptyObject<TransactionState>('transaction');
const savedConfigState = loadStatePropertyOrEmptyObject<ConfigState>('config');
/*
// If they have a saved node, make sure we assign that too. The node selected
// isn't serializable, so we have to assign it here.
if (savedConfigState && savedConfigState.nodes.selectedNode.nodeName) {
const savedNode = getNodeConfigFromId(
savedConfigState.nodeSelection,
savedConfigState.customNodes
);
// If we couldn't find it, revert to defaults
if (savedNode) {
savedConfigState.node = savedNode;
const network = getNetworkConfigFromId(savedNode.network, savedConfigState.customNetworks);
if (network) {
savedConfigState.network = network;
}
} else {
savedConfigState.nodeSelection = configInitialState.nodeSelection;
}
}
// Dedupe custom tokens initially
const savedCustomTokensState =
loadStatePropertyOrEmptyObject<CustomTokenState>('customTokens') || customTokensInitialState;
const initialNetwork =
(savedConfigState && savedConfigState.network) || configInitialState.network;
const customTokens = dedupeCustomTokens(initialNetwork.tokens, savedCustomTokensState);
*/
const persistedInitialState = {
/*
config: {
...configInitialState,
...savedConfigState
},*/
transaction: {
...transactionInitialState,
fields: {
@ -109,18 +72,12 @@ const configureStore = () => {
: transactionInitialState.fields.gasPrice
}
},
// customTokens,
// ONLY LOAD SWAP STATE FROM LOCAL STORAGE IF STEP WAS 3
swap: swapState
swap: swapState,
...rehydrateConfigAndCustomTokenState()
};
// if 'web3' has persisted as node selection, reset to app default
// necessary because web3 is only initialized as a node upon MetaMask / Mist unlock
/*
if (persistedInitialState.config.nodeSelection === 'web3') {
persistedInitialState.config.nodeSelection = configInitialState.nodeSelection;
}
*/
store = createStore(RootReducer, persistedInitialState, middleware);
// Add all of the sagas to the middleware
@ -132,14 +89,6 @@ const configureStore = () => {
throttle(() => {
const state = store.getState();
saveState({
/*
config: {
nodeSelection: state.config.nodeSelection,
languageSelection: state.config.languageSelection,
customNodes: state.config.customNodes,
customNetworks: state.config.customNetworks,
setGasLimit: state.config.setGasLimit
},*/
transaction: {
fields: {
gasPrice: state.transaction.fields.gasPrice
@ -160,7 +109,7 @@ const configureStore = () => {
allIds: []
}
},
customTokens: state.customTokens
...getConfigAndCustomTokensStateToSubscribe(state)
});
}, 50)
);