refactor: state++
This commit is contained in:
parent
eb46f3a591
commit
785ab39bbd
|
@ -1,27 +1,14 @@
|
|||
import merge from 'deepmerge';
|
||||
import {combineReducers} from 'redux';
|
||||
import {connectRouter, routerMiddleware} from 'connected-react-router';
|
||||
import {routerMiddleware} from 'connected-react-router';
|
||||
|
||||
import {stateReducer, subscription} from '~/common/state';
|
||||
|
||||
import app from '~/common/state/app';
|
||||
import chat from '~/common/state/chat';
|
||||
import createHistory from '~/common/state/history';
|
||||
import {storageSubscription} from '~/common/state/storage';
|
||||
import user from '~/common/state/user';
|
||||
import usernames from '~/common/state/usernames';
|
||||
import createCommonStore from '~/common/store';
|
||||
|
||||
import {middleware as effectsMiddleware} from './effects';
|
||||
|
||||
export default function createStore(options = {}) {
|
||||
const {history} = options;
|
||||
const reducer = combineReducers({
|
||||
app,
|
||||
chat,
|
||||
history: createHistory(history),
|
||||
router: connectRouter(history),
|
||||
user,
|
||||
usernames,
|
||||
});
|
||||
const store = createCommonStore(
|
||||
merge(
|
||||
options,
|
||||
|
@ -30,10 +17,10 @@ export default function createStore(options = {}) {
|
|||
routerMiddleware(history),
|
||||
effectsMiddleware,
|
||||
],
|
||||
reducer,
|
||||
reducer: stateReducer(history),
|
||||
},
|
||||
),
|
||||
);
|
||||
store.subscribe(storageSubscription(store));
|
||||
store.subscribe(subscription(store));
|
||||
return store;
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@ export const rightIsOpenSelector = createSelector(
|
|||
);
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'app',
|
||||
initialState: storage(appSelector) || {
|
||||
name: 'reddichat/app',
|
||||
initialState: {
|
||||
leftActiveIndex: 0,
|
||||
leftIsOpen: true,
|
||||
rightActiveIndex: 0,
|
||||
rightIsOpen: true,
|
||||
...(storage(appSelector) || {}),
|
||||
},
|
||||
/* eslint-disable no-param-reassign */
|
||||
extraReducers: {},
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
/* eslint-disable no-param-reassign */
|
||||
import {
|
||||
createSelector,
|
||||
createSlice,
|
||||
} from '@reduxjs/toolkit';
|
||||
|
||||
import hydration from './hydration';
|
||||
import storage from './storage';
|
||||
import storage, {localStorage} from './storage';
|
||||
|
||||
export const chatSelector = (state) => state.chat;
|
||||
|
||||
|
@ -45,7 +44,7 @@ export const channelMessagesSelector = createSelector(
|
|||
);
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'chat',
|
||||
name: 'reddichat/chat',
|
||||
initialState: {
|
||||
channels: {},
|
||||
input: {},
|
||||
|
@ -53,6 +52,10 @@ const slice = createSlice({
|
|||
...(hydration('chat') || {}),
|
||||
...(storage(chatSelector) || {}),
|
||||
},
|
||||
/* eslint-disable no-param-reassign */
|
||||
extraReducers: {
|
||||
[localStorage]: ({input}) => ({input}),
|
||||
},
|
||||
reducers: {
|
||||
addMessage: ({
|
||||
channels,
|
||||
|
@ -117,6 +120,7 @@ const slice = createSlice({
|
|||
submitLeave: () => {},
|
||||
submitMessage: () => {},
|
||||
},
|
||||
/* eslint-enable no-param-reassign */
|
||||
});
|
||||
|
||||
export const {
|
||||
|
|
27
src/common/state/index.js
Normal file
27
src/common/state/index.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import {connectRouter} from 'connected-react-router';
|
||||
import {combineReducers} from 'redux';
|
||||
|
||||
import app from './app';
|
||||
import chat from './chat';
|
||||
import createHistory from './history';
|
||||
import {storageSubscription} from './storage';
|
||||
import user from './user';
|
||||
import usernames from './usernames';
|
||||
|
||||
export const stateReducer = (history) => combineReducers({
|
||||
app,
|
||||
chat,
|
||||
history: createHistory(history),
|
||||
router: connectRouter(history),
|
||||
user,
|
||||
usernames,
|
||||
});
|
||||
|
||||
const subscriptionReducer = combineReducers({
|
||||
app,
|
||||
chat,
|
||||
user,
|
||||
usernames,
|
||||
});
|
||||
|
||||
export const subscription = (store) => storageSubscription(store, subscriptionReducer);
|
|
@ -1,11 +1,22 @@
|
|||
import throttle from 'lodash.throttle';
|
||||
import {createAction} from '@reduxjs/toolkit';
|
||||
|
||||
export const storageSubscription = (store) => (
|
||||
throttle(() => localStorage.setItem('redux-state', JSON.stringify(store.getState())), 1000)
|
||||
export const localStorage = createAction('reddichat/localStorage');
|
||||
|
||||
export const storageSubscription = (store, reducer) => (
|
||||
throttle(
|
||||
() => (
|
||||
window.localStorage.setItem(
|
||||
'redux-state',
|
||||
JSON.stringify(reducer(store.getState(), localStorage())),
|
||||
)
|
||||
),
|
||||
1000,
|
||||
)
|
||||
);
|
||||
|
||||
export default (selector) => {
|
||||
const state = localStorage.getItem('redux-state');
|
||||
const state = window.localStorage.getItem('redux-state');
|
||||
if (!state) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {LOCATION_CHANGE} from 'connected-react-router';
|
||||
import merge from 'deepmerge';
|
||||
import {
|
||||
createSelector,
|
||||
createSlice,
|
||||
|
@ -7,6 +8,7 @@ import {
|
|||
import {addMessage, join, leave} from './chat';
|
||||
|
||||
import hydration from './hydration';
|
||||
import storage, {localStorage} from './storage';
|
||||
|
||||
export const userSelector = (state) => state.user;
|
||||
|
||||
|
@ -104,20 +106,46 @@ export const unreadForChannelSelector = createSelector(
|
|||
);
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'user',
|
||||
initialState: {
|
||||
blocked: [],
|
||||
favorites: [],
|
||||
focus: '',
|
||||
friendship: [],
|
||||
id: 0,
|
||||
isAnonymous: false,
|
||||
recent: [],
|
||||
redditUsername: 'anonymous',
|
||||
unread: {},
|
||||
...(hydration('user') || {isAnonymous: true}),
|
||||
},
|
||||
name: 'reddichat/user',
|
||||
initialState: merge.all([
|
||||
{
|
||||
blocked: [],
|
||||
favorites: [],
|
||||
focus: '',
|
||||
friendship: [],
|
||||
id: 0,
|
||||
isAnonymous: false,
|
||||
recent: [],
|
||||
redditUsername: 'anonymous',
|
||||
unread: {},
|
||||
},
|
||||
hydration('user') || {isAnonymous: true},
|
||||
storage(userSelector) || {},
|
||||
], {arrayMerge: (target, source) => Array.from(new Set(source.concat(target)).values())}),
|
||||
/* eslint-disable no-param-reassign */
|
||||
extraReducers: {
|
||||
[addMessage]: ({focus, unread}, {payload: {channel}}) => {
|
||||
if (focus !== channel) {
|
||||
unread[channel] = (unread[channel] || 0) + 1;
|
||||
}
|
||||
},
|
||||
[join]: ({recent}, {payload: {channel}}) => {
|
||||
if (-1 === recent.indexOf(channel)) {
|
||||
recent.push(channel.substr(3));
|
||||
}
|
||||
},
|
||||
[leave]: ({unread}, {payload: {channel}}) => {
|
||||
delete unread[channel];
|
||||
},
|
||||
[localStorage]: ({recent}) => ({recent}),
|
||||
[LOCATION_CHANGE]: (state, {payload: {location: {pathname}}}) => {
|
||||
const {unread} = state;
|
||||
state.focus = pathname.match(/^\/chat\//) ? pathname.substr('/chat'.length) : '';
|
||||
if (unread[state.focus]) {
|
||||
delete unread[state.focus];
|
||||
}
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
addFriendship: ({friendship}, {payload}) => {
|
||||
const index = friendshipIndex(friendship, payload);
|
||||
|
@ -156,28 +184,6 @@ const slice = createSlice({
|
|||
blocked.splice(blocked.indexOf(payload), 1);
|
||||
},
|
||||
},
|
||||
extraReducers: {
|
||||
[addMessage]: ({focus, unread}, {payload: {channel}}) => {
|
||||
if (focus !== channel) {
|
||||
unread[channel] = (unread[channel] || 0) + 1;
|
||||
}
|
||||
},
|
||||
[join]: ({recent}, {payload: {channel}}) => {
|
||||
if (-1 === recent.indexOf(channel) && channel.charCodeAt(1) === 'r'.charCodeAt(0)) {
|
||||
recent.push(channel.substr(3));
|
||||
}
|
||||
},
|
||||
[leave]: ({unread}, {payload: {channel}}) => {
|
||||
delete unread[channel];
|
||||
},
|
||||
[LOCATION_CHANGE]: (state, {payload: {location: {pathname}}}) => {
|
||||
const {unread} = state;
|
||||
state.focus = pathname.match(/^\/chat\//) ? pathname.substr('/chat'.length) : '';
|
||||
if (unread[state.focus]) {
|
||||
delete unread[state.focus];
|
||||
}
|
||||
},
|
||||
},
|
||||
/* eslint-enable no-param-reassign */
|
||||
});
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from '~/common/state/chat';
|
||||
|
||||
import hydration from './hydration';
|
||||
import storage from './storage';
|
||||
|
||||
export const usernamesSelector = (state) => state.usernames;
|
||||
|
||||
|
@ -17,10 +18,13 @@ export const usernameSelector = createSelector(
|
|||
(usernames, id) => usernames[id],
|
||||
);
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
const slice = createSlice({
|
||||
name: 'usernames',
|
||||
initialState: hydration('usernames') || {},
|
||||
name: 'reddichat/usernames',
|
||||
initialState: {
|
||||
...(hydration('usernames') || {}),
|
||||
...(storage(usernamesSelector) || {}),
|
||||
},
|
||||
/* eslint-disable no-param-reassign */
|
||||
extraReducers: {
|
||||
[join]: (state, {payload: {usernames}}) => ({...state, ...usernames}),
|
||||
[joined]: (state, {payload: {id, name}}) => ({...state, [id]: name}),
|
||||
|
@ -28,8 +32,8 @@ const slice = createSlice({
|
|||
reducers: {
|
||||
setUsernames: (state, {payload}) => ({...state, ...payload}),
|
||||
},
|
||||
/* eslint-enable no-param-reassign */
|
||||
});
|
||||
/* eslint-enable no-param-reassign */
|
||||
|
||||
export const {
|
||||
setUsernames,
|
||||
|
|
Loading…
Reference in New Issue
Block a user