Skip to content

Instantly share code, notes, and snippets.

@amygrinn
Last active December 6, 2018 06:14
Show Gist options
  • Save amygrinn/daf804c2994ae227343dd30aab91fb9e to your computer and use it in GitHub Desktop.
Save amygrinn/daf804c2994ae227343dd30aab91fb9e to your computer and use it in GitHub Desktop.
Redux Module Example (device)
// Example usage of device module selectors in Vue component
import Vue from 'vue';
import { smallerOrEqTo } from './modules/device';
export default Vue.extend({
subscriptions() { return {
mobile: this.$store.select$(smallerOrEqTo('phablet'))
}; }
})
import { Action } from 'redux';
export const SCREEN_SIZE_CHANGE = 'device: Screen Size Change';
export class ScreenSizeChange implements Action {
public readonly type = SCREEN_SIZE_CHANGE;
constructor(public size: { width: number, height: number }) { }
}
import { Channel, eventChannel } from 'redux-saga';
export default class {
public static getResizeChannel(): Channel<boolean> {
return eventChannel((emitter) => {
const listener = () => emitter(true);
if (typeof window !== 'undefined') {
window.addEventListener('resize', listener);
}
// return unsubscribe function
return () => {
if (typeof window !== 'undefined') {
window.removeEventListener('resize', listener);
}
};
});
}
public static getScreenSize(): { width: number, height: number } {
if (typeof window !== 'undefined') {
return {
height: window.innerHeight,
width: window.innerWidth
};
} else {
return { width: 0, height: 0 };
}
}
}
import { Reducer } from 'redux';
import * as Actions from './device.actions';
import { Device, DeviceState, initialState } from './device.state';
const deviceReducer: Reducer<DeviceState> = (state = initialState, action) => {
switch (action.type) {
case Actions.SCREEN_SIZE_CHANGE:
let device: Device;
if (action.size.width <= 480) {
device = 'phone';
} else if (action.size.width <= 839) {
device = 'phablet';
} else if (action.size.width <= 1024) {
device = 'tablet';
} else {
device = 'desktop';
}
return { ...state, screenSize: action.size, device };
default: return state;
}
};
export default deviceReducer;
import { call, put, take } from 'redux-saga/effects';
import * as Actions from './device.actions';
import Api from './device.api';
export function* screenSize() {
const screenSizeChan = yield call(Api.getResizeChannel);
while (true) {
const newSize = yield call(Api.getScreenSize);
yield put({ ...new Actions.ScreenSizeChange(newSize) });
yield take(screenSizeChan);
}
}
export function* deviceSaga(): any {
yield call(screenSize);
}
export default deviceSaga;
import { Selector } from '../../store';
import { DEVICE } from './DEVICE';
import { Device, DeviceState } from './device.state';
const getState: Selector<DeviceState> = (state) => state[DEVICE];
export const getScreenSize: Selector<{ width: number, height: number }> = (state) => getState(state).screenSize;
export const getDevice: Selector<Device> = (state) => getState(state).device;
export const smallerOrEqTo: (device: Device) => Selector<boolean> = (device) => (state) => {
switch (getDevice(state)) {
case 'phone': if (device === 'phone') { return true; }
case 'phablet': if (device === 'phablet') { return true; }
case 'tablet': if (device === 'tablet') { return true; }
case 'desktop': if (device === 'desktop') { return true; }
default: return false;
}
};
export type Device =
'phone'
| 'phablet'
| 'tablet'
| 'desktop';
export class DeviceState {
public screenSize: { width: number, height: number };
public device: Device;
}
export const initialState: DeviceState = {
device: 'desktop',
screenSize: { width: 1920, height: 1080 }
};
export const DEVICE = 'device';
import { ReducersMapObject } from 'redux';
export * from './device.actions';
export * from './device.selectors';
import { DEVICE } from './DEVICE';
import deviceReducer from './device.reducer';
import saga from './device.saga';
export const reducer: ReducersMapObject = {
[DEVICE]: deviceReducer
};
export { saga };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment