Схема кэширования списка страниц H5

внешний интерфейс
Схема кэширования списка страниц H5

Это 95-я оригинальная статья без воды. Если вы хотите получить больше оригинальных статей, выполните поиск в общедоступном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Схема кэширования списка страниц H5

的卢.png

предисловие

При ежедневной разработке H5 часто встречается, что список щелкает, чтобы перейти на страницу сведений, а затем возвращается к списку.Это особенно характерно для платформ электронной коммерции, таких как Taobao, JD.com и других платформ электронной коммерции. мы обычно используем кэширование, и не только List, кэш используется во многих местах. Но то, что я только что сказал, относится ко всем приложениям.LastPageНа странице состояние предыдущей страницы может быть сохранено естественно, но H5 отличается.После возврата из реквизитов в список состояние будет очищено, а после повторного прохождения жизненного цикла запрос будет пере- инициируется, и будет записано новое состояние.Для интерфейса подкачки список очень длинный.Когда пользователь перевернул несколько страниц, щелкните сведения, чтобы просмотреть сведения о продукте, а затем вернуться к списку.В это время страница возвращается на первую страницу, поэтому взаимодействие с пользователем очень плохое Если данные списка кэшируются при вводе сведений Когда вы возвращаетесь к списку, используйте кэшированные данные вместо повторного запроса данных и оставайтесь в позиции просмотра, когда вы покинули список страницу; или вы можете складывать страницы слой за слоем, как приложение.LastPage, отображать соответствующую страницу при возврате, так что пользовательский опыт будет намного лучше. В этой статье кратко представлены некоторые моменты, которые следует учитывать при кэшировании списка, и прилагается простая реализация.

считать

Причина потери статуса

Обычно при разработке страниц мы управляем разными страницами посредством маршрутизации, и существует множество широко используемых библиотек маршрутизации, таких как:React-Router,Dva-router...... Когда мы меняем маршруты, ничего не совпадаетComponentОн также будет заменен целиком, и исходное состояние также потеряно, поэтому, когда пользователь возвращается со страницы сведений на страницу списка, компонент страницы списка будет перезагружен, и жизненный цикл будет перезапущен, и будут получены данные первой страницы.Это возвращает нас к началу списка, а ниже приведены часто используемые фрагменты кода сопоставления маршрутов.

function RouterConfig({ history, app }) {
  const routerData = getRouterData(app);
  return (
    <ConnectedRouter history={history}>
      <Route
        path="/"
        render={(props) => <Layouts routerData={routerData} {...props} />}
        redirectPath="/exception/403"
      />
    </ConnectedRouter>
  );
}
// 路由配置说明(你不用加载整个配置,
// 只需加载一个你想要的根路由,
// 也可以延迟加载这个配置)。
React.render((
  <Router>
    <Route path="/" component={App}>
      <Route path="about" component={About}/>
      <Route path="users" component={Users}>
        <Route path="/user/:userId" component={User}/>
      </Route>
      <Route path="*" component={NoMatch}/>
    </Route>
  </Router>
), document.body)

Как решить

Причина найдена, так как же кэшировать страницы или данные? Обычно есть два решения: 1. Автоматически сохранять состояние при переключении маршрутизации. 2. Вручную сохраните состояние. существуетVue, вы можете использовать его напрямуюkeep-aliveЧтобы реализовать кэширование компонентов, если вы используетеkeep-aliveКомпонент, обернутый меткой, будет автоматически кэшироваться при переключении страницы.失活Компонент очень удобен в использовании, простой пример таков.

<!-- 失活的组件将会被缓存!-->
<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

но,Reactне вkeep-aliveЭтот аналогичный ярлык или функция,Чиновники считают, что эта функция может вызвать утечку памяти, и поддержка пока не рассматривается..

Следовательно, мы можем делать трюки только на уровне маршрутизации и выполнять соответствующую операцию кэширования при переключении маршрута.Некоторые разработчики уже предлагали решение:Управление отображением/скрытием компонентов с помощью стилей, но при этом могут быть проблемы, например, при переключении компонентов нельзя использовать анимацию или использоватьRedux,MobxТакие инструменты управления потоком данных, а также разработчики черезReact.createPortal APIДостигнутоReactверсияReact Keep Alive, и пользоваться им удобнее. Второе решение — вручную сохранить состояние, то есть вручную собрать и сохранить состояние страницы при ее выгрузке и восстановить данные при монтировании страницы. Кэш-кеш — это не что иное, как две вещи: хранение и извлечение, так на какие же проблемы стоит обратить внимание в процессе хранения и извлечения?

Вот несколько вещей, которые я лично считаю необходимым отметить:

Сохранить что? Когда он будет сохранен? Где он существует? Когда принимать? Где взять?

что сохранить

Первое, о чем нам нужно позаботиться: что сохранять? Поскольку мы хотим кэшировать, что мы хотим хранить? заключается в кэшировании всегоComponent, список данных или контейнер прокруткиscrollTop. Например, статьи в официальной учетной записи WeChat кэшируются, нажмите на статью для просмотра, закройте и выйдите после просмотра на полпути, и когда вы снова откроете статью, она останется на предыдущей позиции, и вы можете проверить это самостоятельно, снова При открытии происходит повторное получение данных статьи. В этом сценарии высота прокрутки контейнера прокрутки сведений о статье кэшируется и сохраняется при выходе со страницы. При повторном входе данные получаются, а затем перескакивают на предыдущую высоты.Кроме того, есть много других способов кэширования, можно кэшировать всю страницу, кэшироватьstateданные и т. д., они могут достичь желаемого эффекта, и какой из них использовать, зависит от конкретного бизнес-сценария.

когда сохранять

Во-вторых, что нам нужно учитывать, так это когда сохранять, будет много видов переходов по страницам.actionНавигационные операции, такие как:POP,PUSH,REPLACEи т. д., когда мы комбинируем некоторые из более общих библиотек маршрутизации,actionбудет более подробно, для разныхactionМетоды обработки различны в разных бизнес-сценариях.В качестве примера возьмем публичный аккаунт WeChat.Страница сведений о статье не является хранилищем мозгов, будь тоPUSH,POPДанные о высоте будут сохранены, поэтому независимо от того, сколько раз мы переходим на страницу, мы всегда можем перейти к позиции, с которой мы ушли, когда снова откроем ее.List -> Detail -> ListКэширование может понадобиться, но пользователь начинает сList Введите снова после возврата на другую страницуListПри входе на новую страницу, по логике вещей, ранее кэшированные данные не должны использоваться, а данные должны быть перевыгружены. Правильный путь должен бытьPUSHэкономить во время работы,POPвремя взять.

где существует

  1. Постоянный кеш. Если данные являются постоянными, они могут быть сохранены вURLилиlocalStorageВходURLОдним из положительных моментов этого является то, что он детерминирован и легко распространяется. ноURLможет сначалаpass, потому что в случае сложных списков нужно хранить больше данных, и все они хранятся вURLнереально, и даже если бы это было возможно, это сделало быURLЭто кажется чрезвычайно многословным и явно неуместным.localStorageэто способ обеспечитьgetItem,setItemAPI также достаточно для поддержки операций доступа, максимальная поддержка составляет 5M, а пропускная способность также достаточна за счет сериализации.SerializeИнтеграция также может удовлетворить потребности, кромеIndexDBЭто также хороший способWebSQLОн был заброшен и не будет рассматриваться. Чтобы узнать подробности, нажмите на эту статью Чжан Синьсюй.«Руководство по экземпляру базы данных внешнего локального хранилища HTML5 indexedDB»Посмотрите сравнение.
  2. ОЗУ. Для списков или данных, которые не нужно сохранять, может быть лучшим способом поместить их в память.Если часто выполняются операции чтения и записи, операции ввода-вывода в памяти выполняются быстро и удобно. Поэтому его можно поместить вreduxилиrematchВ других инструментах управления состоянием очень удобно инкапсулировать некоторые общие методы доступа, для общих одностраничных приложений это также можно разместить в глобальномwindowсередина.

Когда принимать

Назад, когда берется в кеш страницы, есть несколько случаев, взятых

  1. Когда действие навигацииPOPвремя, потому что всякий разPUSHПри входе на новую страницу кэшированные данные в этом случае использоваться не должны.
  2. Независимо от того, какая операция навигации предназначена для извлечения данных, эту ситуацию необходимо рассматривать вместе с тем, когда сохранять.
  3. Посмотрите на конкретный бизнес-сценарий, чтобы оценить время принятия.

где это взять

Проблема очень проста, бери ее оттуда, где она есть.

CacheHocплан

  • Что хранить: данные списка + высота прокрутки контейнера прокрутки
  • Когда сохранять: страница уходит, а действие навигацииPUSH
  • где:window
  • Когда принимать: фаза инициализации страницы и действие навигацииPOPкогда
  • Где получить:window

CacheHocЭто высокоуровневый компонент, и кэшированные данные хранятся единообразно вwindowвнутри, черезCACHE_STORAGEКонвергенция, внешнее нужно только передать вCACHE_NAME,scrollElRefsВот и все,CACHE_NAMEэквивалент кэшированных данныхkeyscrollElRefsЭто массив, содержащий контейнеры с прокруткой. Зачем использовать массив? Учитывая ситуацию с несколькими контейнерами с прокруткой на странице, вcomponentWillUnmountЗапишите соответствующий контейнер прокрутки в функцию жизненного цикла.scrollTop,state,существуетconstructorв этомstate,существуетcomponentDidMountобновление вscrollTop.

Простой в использовании

import React from 'react'
import { connect } from 'react-redux'
import cacheHoc from 'utils/cache_hoc'

@connect(mapStateToProps, mapDispatch)
@cacheHoc
export default class extends React.Component {
  constructor (...props) {
    super(...props)
    this.props.withRef(this)
  }

  // 设置 CACHE_NAME
  CACHE_NAME = `customerList${this.props.index}`;
  
  scrollDom = null

  state = {
    orderBy: '2',
    loading: false,
    num: 1,
    dataSource: [],
    keyWord: undefined
  }

  componentDidMount () {
    // 设置滚动容器list
    this.scrollElRefs = [this.scrollDom]
    // 请求数据,更新 state
  }

  render () {
    const { history } = this.props
    const { dataSource, orderBy, loading } = this.state

    return (
      <div className={gcmc('wrapper')}>
        <MeScroll
          className={gcmc('wrapper')}
          getMs={ref => (this.scrollDom = ref)}
          loadMore={this.fetchData}
          refresh={this.refresh}
          up={{
            page: {
              num: 1, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
              size: 15 // 每页数据的数量
              // time: null // 加载第一页数据服务器返回的时间; 防止用户翻页时,后台新增了数据从而导致下一页数据重复;
            }
          }}
          down={{ auto: false }}
        >
          {loading ? (
            <div className={gcmc('loading-wrapper')}>
              <Loading />
            </div>
          ) : (
            dataSource.map(item => (
              <Card
                key={item.clienteleId}
                data={item}
                {...this.props}
                onClick={() =>
                  history.push('/detail/id')
                }
              />
            ))
          )}
        </MeScroll>
        <div className={styles['sort']}>
          <div className={styles['sort-wrapper']} onClick={this._toSort}>
            <span style={{ marginRight: 3 }}>最近下单时间</span>
            <img
              src={orderBy === '2' ? SORT_UP : SORT_DOWN}
              alt='sort'
              style={{ width: 10, height: 16 }}
            />
          </div>
        </div>
      </div>
    )
  }
}

Эффект следующий:

Кэшированные данные:

код

const storeName = 'CACHE_STORAGE'
window[storeName] = {}

export default Comp => {
  return class CacheWrapper extends Comp {
    constructor (props) {
      super(props)
      // 初始化
      if (!window[storeName][this.CACHE_NAME]) {
        window[storeName][this.CACHE_NAME] = {}
      }
      const { history: { action } = {} } = props
      // 取 state
      if (action === 'POP') {
        const { state = {} } = window[storeName][this.CACHE_NAME]
        this.state = {
          ...state,
        }
      }
    }

    async componentDidMount () {
      if (super.componentDidMount) {
        await super.componentDidMount()
      }
      const { history: { action } = {} } = this.props
      if (action !== 'POP') return
      const { scrollTops = [] } = window[storeName][this.CACHE_NAME]
      const { scrollElRefs = [] } = this
      // 取 scrollTop
      scrollElRefs.forEach((el, index) => {
        if (el && el.scrollTop !== undefined) {
          el.scrollTop = scrollTops[index]
        }
      })
    }

    componentWillUnmount () {
      const { history: { action } = {} } = this.props
      if (super.componentWillUnmount) {
        super.componentWillUnmount()
      }
      if (action === 'PUSH') {
        const scrollTops = []
        const { scrollElRefs = [] } = this
        scrollElRefs.forEach(ref => {
          if (ref && ref.scrollTop !== undefined) {
            scrollTops.push(ref.scrollTop)
          }
        })
        window[storeName][this.CACHE_NAME] = {
          state: {
            ...this.state
          },
          scrollTops
        }
      }
      if (action === 'POP') {
        window[storeName][this.CACHE_NAME] = {}
      }
    }
  }
}

Суммировать

ВышеCacheHocЭто просто самая простая реализация, и есть еще много областей для улучшения, таких как: 1. Непосредственное существованиеwindowЭто немного грубо посередине, и многостраничное приложение сохраняется вwindowДанные будут потеряны, вы можете сохранить их вIndexDBилиlocalStorageКроме того, если эта схема не сотрудничает сmescrollнуждаться вcomponentDidMountсудитьstateЕсли есть значение, данные не будут инициализированы.bug.

Существуют различные схемы кэширования, но необходимо учитывать вышеуказанные моменты. Кроме того, когда я говорил о пяти пунктах, требующих внимания, я акцентировал внимание на том, что сохранять и где существовать.На самом деле то, что существует, не слишком важно, и не нужно слишком заботиться.Просто найдите подходящее место, чтобы сохранить его, и что более важно, что сохранить, Когда сохранить, вам нужно выбрать соответствующий метод, основанный на фактическом сценарии приложения. На разных страницах могут использоваться разные методы. Нет фиксированного плана. Важно то, для анализа времени и места доступа.

Рекомендуемое чтение

Как реализовать бинарную кучу с помощью JS

Написание высококачественного поддерживаемого кода: парадигма программы

Карьера

ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 40 фронтенд-партнеров, средний возраст которых составляет 27 лет, и почти 30% из них — инженеры полного стека, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.

Если вы хотите измениться, вас забросали вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года опыта работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com