J'ai déjà visité le
référentiel de la bibliothèque
redux , mais de quelque part j'ai eu l'idée de me plonger dans son implémentation. J'aimerais partager ma découverte choquante ou même décevante avec la communauté.
TL; DR: La logique de redux de base tient dans 7 lignes de code JS.
À propos de redux en bref (traduction gratuite de l'en-tête sur le github):
Redux est une bibliothèque de gestion d'état pour les applications JavaScript.
Il aide à écrire des applications qui se comportent de manière stable / prévisible, fonctionnent dans différents environnements (client / serveur / code natif) et sont facilement testées.
J'ai
cloné le référentiel redux , ouvert le dossier source dans l'éditeur (en ignorant les
documents , les
exemples , etc.) et
saisi la clé Supprimer avec les
ciseaux :
- Suppression de tous les commentaires du code
Chaque méthode de bibliothèque est documentée en détail à l'aide de JSDoc.
- Suppression de la validation et de la journalisation des erreurs
Dans chaque méthode, les paramètres d'entrée sont étroitement contrôlés avec la sortie de très beaux commentaires détaillés à la console
- Suppression de bindActionCreators , subscribe , replaceReducer et méthodes observables .
... parce qu'il le pouvait. Eh bien, ou parce que j'étais trop paresseux pour leur écrire des exemples. Mais sans cas d'angle, ils sont encore moins intéressants que ce qui nous attend.
Voyons maintenant ce qui reste
Écriture redux en 7 lignes
Toutes les fonctionnalités de base de redux tiennent dans un petit fichier, pour lequel presque personne ne créera un dépôt github :)
function createStore(reducer, initialState) {
let state = initialState
return {
dispatch: action => { state = reducer(state, action) },
getState: () => state,
}
}
. , ,
.
redux. 18 HeadHunter «redux» — , , 7 . — .
7 TodoApp. .
TodoApp redux.
function todosReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
]
case 'TOGGLE_TODO':
return state.map(todo => {
if (todo.id === action.id) {
return { ...todo, completed: !todo.completed }
}
return todo
})
default:
return state
}
}
const initialTodos = []
const store = createStore(todosReducer, initialTodos)
store.dispatch({
type: 'ADD_TODO',
id: 1,
text: ' redux '
})
store.getState()
store.dispatch({
type: 'TOGGLE_TODO',
id: 1
})
store.getState()
,
show must go on.
, .
combineReducers
, , reducer , .
:
function counterReducer(state, action) {
if (action.type === 'ADD') {
return state + 1
} else {
return state
}
}
const reducer = combineReducers({
todoState: todoReducer,
counterState: counterReducer
})
const initialState = {
todoState: [],
counterState: 0,
}
const store = createStore(reducer, initialState)
store , .
TodoApp .
ES6 (7/8/∞):
const reducer = combineReducers({ todos, counter })
todoReducer todos counterReducer counter. . , , redux, ,
(state.todos) ,
(function todos(){}).
micro-redux, :
function reducer(state, action) {
return {
todoState: todoReducer(state, action),
counterState: counterReducer(state, action),
}
}
. 2 «-»,
(state, action),
, ?, Object.entries
combineReducers (, )
:
function combineReducers(reducersMap) {
return function combinationReducer(state, action) {
const nextState = {}
Object.entries(reducersMap).forEach(([key, reducer]) => {
nextState[key] = reducer(state[key], action)
})
return nextState
}
}
redux 9 .
, , .
applyMiddleware
middleware redux — - , dispatch
-. , , ,… —
-.
middleware createStore, , :
const createStoreWithMiddleware = applyMiddleware(someMiddleware)(createStore)
const store = createStoreWithMiddleware(reducer, initialState)
applyMiddleware, 10 , : createStore «dispatch». dispatch, ( ) , — , (newState = reducer(state, action)).
applyMiddleware
dispatch, ( ) - .
, , middleware redux —
redux-thunk,
store.dispatch({type: 'SOME_ACTION_TYPE', some_useful_data: 1 })
store.dispatch
function someStrangeAction() {
return async function(dispatch, getState) {
if(getState().counterState % 2) {
dispatch({
type: 'ADD',
})
}
await new Promise(resolve => setTimeout(resolve, 1000))
dispatch({
type: 'TOGGLE_TODO',
id: 1
})
}
}
,
dispatch(someStrangeAction())
:
- store.getState().counterState 2, 1
- , todo id=1 completed true false .
, redux-thunk, redux — , ,
:
const thunk = store => dispatch => action => {
if (typeof action === 'function') {
return action(store.dispatch, store.getState)
}
return dispatch(action)
}
,
const thunk = store => dispatch => action
, , , , , (, , )
,
createStorefunction createStore(reducer, initialState) {
let state = initialState
return {
dispatch: action => { state = reducer(state, action) },
getState: () => state,
}
}
(reducer, initialState) { dispatch, getState }.
,
applyMiddleware , , .
createStore :
function applyMiddleware(middleware) {
return function createStoreWithMiddleware(createStore) {
return (reducer, state) => {
const store = createStore(reducer, state)
return {
dispatch: action => middleware(store)(store.dispatch)(action),
getState: store.getState,
}
}
}
}
redux . « , ». , 1 — .
P.S.
«micro-redux» store.subscribe 8 . ?