DeanPaul / blog

MIT License
2 stars 1 forks source link

React-Router-Redux source code #39

Open DeanPaul opened 6 years ago

DeanPaul commented 6 years ago

react-router-redux

它是由5个js文件构成 index.js action.js reducer.js middleware.js sync.js

DeanPaul commented 6 years ago

index.js

对外暴露的接口文件

export syncHistoryWithStore from './sync'
export { LOCATION_CHANGE, routerReducer } from './reducer'

export {
  CALL_HISTORY_METHOD,
  push, replace, go, goBack, goForward,
  routerActions
} from './actions'
export routerMiddleware from './middleware'
DeanPaul commented 6 years ago

action.js

基本上来说是给自己的middleware使用的 主要功能是操作 history的一些函数,这里的history指的是hashHistroy或者boswerHistroy,它们都来自于react-router

/**
 * This action type will be dispatched by the history actions below.
 * If you're writing a middleware to watch for navigation events, be sure to
 * look for actions of this type.
 */
export const CALL_HISTORY_METHOD = '@@router/CALL_HISTORY_METHOD'

function updateLocation(method) {
  return (...args) => ({
    type: CALL_HISTORY_METHOD,
    payload: { method, args }
  })
}

/**
 * These actions correspond to the history API.
 * The associated routerMiddleware will capture these events before they get to
 * your reducer and reissue them as the matching function on your history.
 */
export const push = updateLocation('push')
export const replace = updateLocation('replace')
export const go = updateLocation('go')
export const goBack = updateLocation('goBack')
export const goForward = updateLocation('goForward')

export const routerActions = { push, replace, go, goBack, goForward }
DeanPaul commented 6 years ago

middleware.js

主要作用是拦截CALL_HISTORY_METHOD ,执行history的部分函数

export default function routerMiddleware(history) {
  return () => next => action => {
    if (action.type !== CALL_HISTORY_METHOD) {
      return next(action)
    }

    const { payload: { method, args } } = action
    history[method](...args)
  }
}
DeanPaul commented 6 years ago

reducer.js

export const LOCATION_CHANGE = '@@router/LOCATION_CHANGE'
export function routerReducer(state = initialState, { type, payload } = {}) {
  if (type === LOCATION_CHANGE) {
    return { ...state, locationBeforeTransitions: payload }
  }

  return state
}
DeanPaul commented 6 years ago

sync.js

const defaultSelectLocationState = state => state.routing//默认是在此获取

handleStoreChange

注册在store上一个listener,在每次dispatch后调用,对比currentLocation和locationInStore是否相同,若不相同,则将locationInStore更新为currentLocation,并history.transitionTo(执行location的改变)

handleLocationChange

history.listen(handleLocationChange) 当location发生改变,store.dispatch({ type: LOCATION_CHANGE, payload: location })

  const getLocationInStore = (useInitialIfEmpty) => {
    const locationState = selectLocationState(store.getState())
    return locationState.locationBeforeTransitions ||
      (useInitialIfEmpty ? initialLocation : undefined)
  }
  initialLocation = getLocationInStore()
  if (adjustUrlOnReplay) {
    const handleStoreChange = () => {
      const locationInStore = getLocationInStore(true)
      if (currentLocation === locationInStore || initialLocation === locationInStore) {
        return
      }
      isTimeTraveling = true
      currentLocation = locationInStore
      history.transitionTo({
        ...locationInStore,
        action: 'PUSH'
      })
      isTimeTraveling = false
    }
    unsubscribeFromStore = store.subscribe(handleStoreChange)
    handleStoreChange()
  }
  const handleLocationChange = (location) => {
    if (isTimeTraveling) {
      return
    }
    currentLocation = location
    if (!initialLocation) {
      initialLocation = location
      if (getLocationInStore()) {
        return
      }
    }
    store.dispatch({
      type: LOCATION_CHANGE,
      payload: location
    })
  }
  unsubscribeFromHistory = history.listen(handleLocationChange)