regionjs / rfcs

0 stars 0 forks source link

region.withMiddleware(...).load() #3

Closed dancerphil closed 3 years ago

dancerphil commented 5 years ago

API

const showError = next => (state, action) => {
  const nextState = next(state, action);
  if (nextState.error) {
    message.error(error.message);
  }
  return nextState;
}

const cacheBefore = next => (state, action) => {
  const {params} = action;
  const id = stableStringify(params);
  const nextState = next(state, action);
  if (status === 'pending') {
    nextState.id = id;
    nextState.result = nextState.results[id];
  } else if (status === 'fulfilled') {
    nextState.results[id] = nextState.result;
  }
  return nextState;
}

const cacheExist = next => (state, action) => {
  const {params} = action;
  const id = stableStringify(params);
  const nextState = next(state, action);
  if (status === 'pending' && nextState.results[id]) {
    nextState.id = id;
    nextState.result = nextState.results[id];
  }
  if (status === 'fulfilled') {
    nextState.id = id;
    nextState.results[id] = nextState.result;
  }
  return nextState;
}

const acceptLatest = next => (state, action) => {
  const {promise, status} = action;
  if (status === 'pending') {
    state.pendingQueue.push(promise); // pendingMutex = pendingQueue.length
    return state;
  }
  const isLatest = promise === last(state.pendingQueue);
  state.pendingQueue = sliceBy(promise)(state.pendingQueue);
  if (!isLatest) {
    return state;
  }
  if (status === 'rejected') {
    state.error = action.payload;
    return state;
  }
  const nextResult = next(state.result, action.payload);
  state.result = nextResult;
  return state;
}

const loadUser = region.withMiddleware([showError, cacheExist, acceptLatest]).loadBy(asyncFunction)(params);

Implement

const apply = (middlewares, reducer) =>( state, action) =>{
  let next = reducer
  next = middlewares[1](next)
  next = middlewares[0](next)
  const nextState = next(state, action)
}

const enhance = (region) => {
  region.withMiddleware = (middlewares) => {
    const loadBy = (asyncFunction, reducer) => async params => {
      const promise = asyncFunction(params)
      const pendingAction = {
        type: asyncFunction,
        params: params,
        promise: promise,
        status: 'pending',
        payload: undefined,
      }
      const nextState = apply(middlewares, reducer)(region.getProps(), pendingAction)
      region.set(nextState)
      try {
        const payload = await pendingAction.promise
        const resolveAction = {
          type: asyncFunction,
          params: params,
          promise: promise,
          status: 'resolve',
          payload: payload,
        }
        const nextState = apply(middlewares, reducer)(region.getProps(), resolveAction)
        region.set(nextState)
      } catch (e) {
        const rejectAction = {
          type: asyncFunction,
          params: params,
          promise: promise,
          status: 'reject',
          payload: e,
        }
        const nextState = apply(middlewares, reducer)(region.getProps(), rejectAction)
        region.set(nextState)
      }
    }
    return {loadBy}
  }
}