【问题标题】:Rehydrating state from both local storage and URL hash从本地存储和 URL 哈希中恢复状态
【发布时间】:2017-11-30 19:08:12
【问题描述】:

我已经编写了以下 reducer,它可以工作,但感觉我正在进入突变领域,并且可能有更好的方法来实现这一点。我有一个处于阅读状态的对象。读数可以从 URL 中的散列中提取,也可以从存储在读数对象中的称为 oldReadings 的读数记录中提取。第三种方法是从本地存储中的持久状态中提取它。我希望优先考虑 URL 提取以便于共享。这种方法可以吗,如果不行,你能指出我正确的方向吗?

import { GENERATE_READING, GET_READING_FROM_HASH } from '../constants/actionTypes';
import { REHYDRATE } from 'redux-persist/constants';
import getHashFromUrl from '../utils/getHashFromUrl';
import getReadingFromHash from '../utils/getReadingFromHash';

// Check if URL has hash and set initial state to that reading.
const initialUrlHash = getHashFromUrl(window.location.pathname);
const initialUrlReading = initialUrlHash ? getReadingFromHash(initialUrlHash) : null;
const initialState = {
  arr: initialUrlReading ? initialUrlReading.arr : [],
  hash: initialUrlHash ? initialUrlHash : '',
  time: 0,
  oldReadings: []
};

export const reading = (state = initialState, action) => {
  switch (action.type) {
    case GENERATE_READING: {
      let reading = action.reading;
      // If old readings exists, save new reading to array of old readings.
      if (state.oldReadings) {
        reading.oldReadings = [ {
          hash: reading.hash,
          time: reading.time,
          amount: reading.arr.length
        }, ...state.oldReadings ];
        reading.oldReadings = reading.oldReadings.slice(0, 5);
      }
      // Otherwise create new array and save reading to it.
      else {
        reading.oldReadings = [{
          hash: reading.hash,
          time: reading.time,
          amount: reading.arr.length
        }];
      }

      return { ...state, ...reading };
    }

    case GET_READING_FROM_HASH:
      // Used when restoring reading for old hash.
      return { ...state, ...action.reading };

    case REHYDRATE: {
      const incoming = action.payload.reading;
      // If hydrating from local storage, check for hash in url and append
      // that reading on top of reading from local storage.
      if (incoming) {
        const urlHash = getHashFromUrl(window.location.pathname);
        if (urlHash && incoming.hash !== urlHash) {
          const urlReading = getReadingFromHash(urlHash);
          return { ...state, ...incoming, ...urlReading };
        } else {
          return { ...state, ...incoming };
        }
      } else {
      return state;
      }
    }

    default:
      return state;
  }
};

export default reading;

【问题讨论】:

    标签: javascript reactjs url redux local-storage


    【解决方案1】:

    我认为您可以使用Object.assign 来避免突变并简化您的代码。例如,而不是let reading = action.reading,它仍然只是对原始对象的引用,您可以执行const reading = Object.assign({}, action.reading)。这实际上需要一个新的空对象并将action.reading复制到其中。看看文档,Object.assign 对于这种类型的东西来说是无价的。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

    【讨论】:

    • 好点!我会确保解决这个问题。我主要担心的是依赖window.location 的“不纯性”,而不仅仅是状态/动作。
    • 当然,这是有道理的。您可以从应用程序包装器的componentDidMount 中分派一个操作,并将window.location.pathname 作为有效负载,这样您就知道该窗口可用。它可能会让事情变得更干净一些。
    • 这听起来真是个好主意,一定会调查的!希望在补液操作之前调度,如果是这样,我可以添加类似 hasSyncedFromUrl 的标志来检查 REHYDRATE 案例。
    猜你喜欢
    • 2023-03-05
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-28
    • 2013-07-21
    • 2012-11-13
    • 1970-01-01
    相关资源
    最近更新 更多