Skip to content

Instantly share code, notes, and snippets.

@staydecent
staydecent / why-redux.md
Created December 3, 2018 16:36
Why Redux over a global setState solution

Why Redux over a more basic Global Store

It's easy to look at Redux and think it's just an overcomplicated global state. You can strip away much of the API and just implement an immutable object state, even mimicking the React state API of just setState and getState.

And, this will get you pretty far. Then, throw in a few helpers to map or select parts of the state object and use them as props in your Components, and you actually have a solution that's very friendly for rapid prototyping. Without the need to create specific Actions and Reducers, you reduce boilerplate, and can just start modifying state from your components: globalStore.setState({todos: globalState.todos.push(newTodo)}).

When creating prototypes or MVPs, where speed is a priority, a simple global store is a good solution. So, why would you bother with the added complexity of Redux, Actions, and Reducers? Well, here's what I've come up with.

Traceable state changes

@staydecent
staydecent / fsm.js
Last active December 1, 2018 23:57
finite state machine, meet global state (redux), meet clean Component implementations
const fsm = {
Init: {
'missing-password': 'PasswordError',
'missing-email': 'EmailError',
'submit': 'Submitting'
},
PasswordError: {
'change-password': 'Ready'
},
EmailError: {
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("prop-types"),require("preact")):"function"==typeof define&&define.amd?define(["prop-types","preact"],t):e.preactCompat=t(e.PropTypes,e.preact)}(this,function(a,p){"use strict";a=a&&a.hasOwnProperty("default")?a.default:a;var e="a abbr address area article aside audio b base bdi bdo big blockquote body br button canvas caption cite code col colgroup data datalist dd del details dfn dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins kbd keygen label legend li link main map mark menu menuitem meta meter nav noscript object ol optgroup option output p param picture pre progress q rp rt ruby s samp script section select small source span strong style sub summary sup table tbody td textarea tfoot th thead time title tr track u ul var video wbr circle clipPath defs ellipse g image line linearGradient mask path pattern polygon polyline radialGr
@staydecent
staydecent / PrintURLs.js
Last active August 14, 2018 03:23
Lil JS to make downloading images from London Drugs film scan pages easier.
imgs = $('.preview > img');
srcs = []
for (let x = imgs.length - 1; x >= 0; x--) {
srcs.push(imgs[x].src.replace('size=240', 'size=0'))
imgs[x].addEventListener('click', ev => {
ev.preventDefault();
window.open(imgs[x].src.replace('size=240', 'size=0'), '_blank');
});
}
console.log(JSON.stringify(srcs))
@staydecent
staydecent / LoadMore.js
Created October 19, 2017 16:58
Load More Higher Order Component for React/Preact etc. (Assumes a JSON-API like response with a `next` property)
import check from 'check-arg-types'
import queryString from 'query-string'
import {set} from 'atom-lens-reducer'
import {
filter,
concat,
map,
merge,
pipe,
pathOr,
@staydecent
staydecent / trello.css
Created October 5, 2017 16:55
Trello styles
@namespace url(http://www.w3.org/1999/xhtml);
.list-card-labels .card-label.mod-card-front {
float: left;
display: block !important;
width: auto;
height: inherit !important;
padding: 0px 4px !important;
margin-right: 0px !important;
margin-left: 0;
border-radius: 2px;
// set, update, remove
// Functions to mutate global state. No need for `dispatch`.
// Since there would only be these functions and no more dispatch,
// there would be no need for reducers.
set('items', [1, 2, 3]) // [1, 2, 3]
update(['items', 1], 'a') // [1, 'a', 3]
// batch(set, update, remove, ...)
@staydecent
staydecent / watchStore.js
Created August 14, 2017 02:39
watch a path on your (Redux or Atom) state tree for value changes
import check from 'check-arg-types'
import pathOr from 'ramda/src/pathOr'
import merge from 'ramda/src/merge'
import {subscribe, getState} from './store' // this is your local store file
const toType = check.prototype.toType
// Cache prev value for given path to allow easy diffing in the listner.
const cache = {}
@staydecent
staydecent / decouple-react-api-calls.md
Last active May 14, 2018 18:28
How to keep API calls decoupled from React components

Keeping API calls decoupled from React components keeps your views pure and without side-effects! This makes it easier to test your views without having to worry about API calls. You can test your API separately from your views.

Some Assumptions

Before I dive any deeper, here are some assumptions: You are using React to render your views (HTML). You are using Redux, or something similar to handle state. Myself, I actually use Preact and Atom instead of React and Redux -- They are both much smaller and their source codes are easy to understand, which I favour. The APIs are basically the same. And, I'm also assuming you rely heavily on Redux/Atom and not on React's setState method.

Moving Request Logic Outside Of Your Views

If you're coming from MVC, then you know your views should be simple and without complex logic. Instead, you would use the Controller to load remote data and do any normalization. But where is the Controller when using React and Redux? There isn't really a controller, but that

@staydecent
staydecent / actions.js
Last active October 19, 2017 17:07
Preact Dropdown
import check from 'check-arg-types'
import createAction from '/util/createAction'
export const TOGGLE_DROPDOWN = 'TOGGLE_DROPDOWN'
const toggleDropdownAction = createAction(TOGGLE_DROPDOWN)
export function toggleDropdown (uid) {
check(arguments, ['string'])
return toggleDropdownAction({uid})