Redux Simple comme un râteau

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() 
// [{ id: 1, text: '  redux ', completed: false }]

store.dispatch({
  type: 'TOGGLE_TODO',
  id: 1
})

store.getState() 
// [{ id: 1, text: '  redux ', completed: true }]

, show must go on.
, .

combineReducers


, , reducer , .

:

//     todosReducer   

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
, , , , , (, , )

, createStore

function 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 . ?

Source: https://habr.com/ru/post/fr439104/


All Articles