Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redux #15

Open
wangbinyq opened this issue Jun 27, 2017 · 2 comments
Open

redux #15

wangbinyq opened this issue Jun 27, 2017 · 2 comments

Comments

@wangbinyq
Copy link
Owner

Redux

createStore

createStore(reducer: (state) => state, preloadedState?: state, enhancer?: Function): {
  dispatch: (action: object) => action,
  subscribe: (listener) => unsubscribe, // subscribe within dispatch will not affects current dispatch, but next dispatch, whether nested or not, will use a more recent snapshot of the subscription list
  getState () => currentState,
  repalceReducer,
  $$observable //Interoperability point for observable/reactive libraries
}

If enhancer is provided, createStore will become enhancer(createStore).

Actions

Actions are the only source of information for the store. You send them to the store using store.dispatch()

Action Creators

Action Creators are functions that create actions. In traditional Flux, action creators often trigger a dispatch when invoked, But not in Redux. You should explicit call the dispatch function or create bound action creator that automatically dispatches.
Action Creators can be asynchronous and have side-effects.

Reducers

Reducers descibe how application's state changes when actions dispatch.
The reducer is a pure function that takes the previous state and an action, and returns the next state.
Reducer function must be pure function, given the same arguments, it should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.

Splitting Reducers

As your application grow , you single reducer function will also grow to very long.
Redux provide combineReducers().

Data Flow

React

Presentational Components Container Components
Purpose How things look (markup, styles) How things work (data fetching, state updates)
Aware of Redux No Yes
To read data Read data from props Subscribe to Redux state
To change data Invoke callbacks from props Dispatch Redux actions
Are written By hand Usually generated by React Redux

Technically you could write the container components by hand using store.subscribe(). We don't advise you to do this because React Redux makes many performance optimizations that are hard to do by hand. For this reason, rather than write container components, we will generate them using the connect() function provided by React Redux.

connect

connect() takes mapStateToProps and mapDispatchToProps and conver a presentational component to container component.

@wangbinyq
Copy link
Owner Author

Advanced

Middleware

function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
       // use local dispatch reference
       // make sure dispatch inside of middleware travel the whole middleware chain again
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

Async Actions

When you calls an asynchronous API, There are two crucial moments in time: the moment you start the call, and the moment when you receive an answer (or a timeout). Each of these two moments usually require a change in application state. So , there are at least three different kinds of actions:

  1. An action informing the reducers that the request began. (set isFetching)
  2. An action informing the reducers that the request finished successfully. (set result and reset isFetching)
  3. An action informing the reducers that the request failed. (set error and reset isFetching)

Async Action Creators

redux-thunk

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }
    
    // next is next middleware or store.dispatch
    // came from funcs.reduce((a, b) => (...args) => a(b(...args)))
    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

redux-promise

import { isFSA } from 'flux-standard-action';

function isPromise(val) {
  return val && typeof val.then === 'function';
}

export default function promiseMiddleware({ dispatch }) {
  return next => action => {
    if (!isFSA(action)) {
      return isPromise(action)
        ? action.then(dispatch)
        : next(action);
    }

    return isPromise(action.payload)
      ? action.payload.then(
          result => dispatch({ ...action, payload: result }),
          error => {
            dispatch({ ...action, payload: error, error: true });
            return Promise.reject(error);
          }
        )
      : next(action);
  };
}

Async Flow

Without middleware, Redux store only supports synchronous data flow. This is what you get by default with createStore().

You may enhance createStore() with applyMiddleware(). It is not required, but it lets you express asynchronous actions in a convenient way.

Asynchronous middleware like redux-thunk or redux-promise wraps the store's dispatch() method and allows you to dispatch something other than actions, for example, functions or Promises. Any middleware you use can then interpret anything you dispatch, and in turn, can pass actions to the next middleware in the chain. For example, a Promise middleware can intercept Promises and dispatch a pair of begin/end actions asynchronously in response to each Promise.

When the last middleware in the chain dispatches an action, it has to be a plain object. This is when the synchronous Redux data flow takes place.

@wangbinyq
Copy link
Owner Author

redux-observable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant