-
Star
(976)
You must be signed in to star a gist -
Fork
(125)
You must be signed in to fork a gist
-
-
Save gaearon/ffd88b0e4f00b22c3159 to your computer and use it in GitHub Desktop.
| function mapValues(obj, fn) { | |
| return Object.keys(obj).reduce((result, key) => { | |
| result[key] = fn(obj[key], key); | |
| return result; | |
| }, {}); | |
| } | |
| function pick(obj, fn) { | |
| return Object.keys(obj).reduce((result, key) => { | |
| if (fn(obj[key])) { | |
| result[key] = obj[key]; | |
| } | |
| return result; | |
| }, {}); | |
| } | |
| function bindActionCreator(actionCreator, dispatch) { | |
| return (...args) => dispatch(actionCreator(...args)); | |
| } | |
| export function bindActionCreators(actionCreators, dispatch) { | |
| return typeof actionCreators === 'function' ? | |
| bindActionCreator(actionCreators, dispatch) : | |
| mapValues(actionCreators, actionCreator => | |
| bindActionCreator(actionCreator, dispatch) | |
| ); | |
| } | |
| export function compose(...funcs) { | |
| return arg => funcs.reduceRight((composed, f) => f(composed), arg); | |
| } | |
| export function applyMiddleware(...middlewares) { | |
| return (next) => (reducer, initialState) => { | |
| var store = next(reducer, initialState); | |
| var dispatch = store.dispatch; | |
| var chain = []; | |
| chain = middlewares.map(middleware => middleware({ | |
| getState: store.getState, | |
| dispatch: (action) => dispatch(action) | |
| })); | |
| dispatch = compose(...chain)(store.dispatch); | |
| return { ...store, dispatch }; | |
| }; | |
| } | |
| export function combineReducers(reducers) { | |
| var finalReducers = pick(reducers, (val) => typeof val === 'function'); | |
| return (state = {}, action) => mapValues(finalReducers, | |
| (reducer, key) => reducer(state[key], action) | |
| ); | |
| } | |
| export function createStore(reducer, initialState) { | |
| var currentReducer = reducer; | |
| var currentState = initialState; | |
| var listeners = []; | |
| var isDispatching = false; | |
| function getState() { | |
| return currentState; | |
| } | |
| function subscribe(listener) { | |
| listeners.push(listener); | |
| return function unsubscribe() { | |
| var index = listeners.indexOf(listener); | |
| listeners.splice(index, 1); | |
| }; | |
| } | |
| function dispatch(action) { | |
| if (isDispatching) { | |
| throw new Error('Reducers may not dispatch actions.'); | |
| } | |
| try { | |
| isDispatching = true; | |
| currentState = currentReducer(currentState, action); | |
| } finally { | |
| isDispatching = false; | |
| } | |
| listeners.slice().forEach(listener => listener()); | |
| return action; | |
| } | |
| function replaceReducer(nextReducer) { | |
| currentReducer = nextReducer; | |
| dispatch({ type: '@@redux/INIT' }); | |
| } | |
| dispatch({ type: '@@redux/INIT' }); | |
| return { dispatch, subscribe, getState, replaceReducer }; | |
| } |
@sag1v found the possible reason, please read the 2nd caveat here https://redux.js.org/api/store#subscribe
@raynerpupo For some reason i missed your comments, thanks :)
For other readers, this code snippet can demonstrate what happens if you don't use .slice to create a "snapshot" of the array.
Basically if a listener removes itself from the array, other listeners might not run (due to mutation).
let arr = [func1, func2];
function func1(){
arr.splice(0, 1) // func1 removes itself from the array
console.log(1)
}
function func2(){
console.log(2)
}
arr
//.slice() // if we don't slice here, func2 wont run
.forEach(fn => fn())
// logs: 12020, starting to learn redux, and got one confusion for this code snippet:
In the createStore function, there should be a third option argument enhancer right? I checked the redux source code and the createStore function might look this:
function createStore(reducer, preloadedState, enhancer) {
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
// ... dispatch, subscribe, getState, replaceReducer,
}In this case we can then pass the applyMiddleware to the createStore function:
const store = createStore(
rootReducer,
applyMiddleware(
thunk,
logger,
)Not sure if my thoughts are reasonable, could someone correct me please?
I did the same for my Redux Course to explain how really Redux works and what is the concept. I notice that in a lot of courses about Redux, teachers miss the importance of selectors...
Could u please share some link to your course? is it available somewhere?
Poetry
@sag1v while that
forEachis a blocking operation it doesn't guarantee that alistener()call wouldn't remove a original listener from thelistenersarray so by copying the list you won't get weird results. 2nd caveat from here: https://redux.js.org/api/store#subscribe.