React列表keep-alive的一種寫法

前言

Route 組件的渲染方式有三種:component,render,children,優先級由高到低css

代碼能夠看 這裏,這與 另一篇 是同樣的,本文只是把這部分單獨拿出來,而那篇文章的內容比較完整,基本上項目裏用到的,能想到的都有了react

效果: git

路由

使用 Route 組件的 render 方法代替經常使用的 component ,使得詳情 Detail 組件掛載在 List 下面,即進入詳情,可是列表並不會被註銷;github

AuthRoute 是封裝官方 Route 的組件,使用 Route 替代也不會有問題antd

import AuthRoute from '@/routes/auth-route';
import * as React from 'react';
import Loadable from '@loadable/component';

const List = Loadable(() => import('@/views/list'));

// 實現列表保留滾動條位置的寫法
// list
export default [
  <AuthRoute 
    key="list" 
    // exact={true} 
    path="/list" 
    // component={Loadable(() => import('@/views/list'))} 
    render={() => {
      return (
        <List>
          <AuthRoute 
            exact={true} 
            path="/list/detail/:id" 
            component={Loadable(() => import('@/views/list-detail'))} 
          />
        </List>
      )
    }}
  />
]
複製代碼

組件

列表:props.children 表明詳情組件 <Detail />,在上面的路由文件能夠看到;react-router

列表滾動時記錄滾動條位置,從詳情返回列表時恢復滾動條位置,從而實現 keep-alive 的效果post

從列表到詳情則重置滾動條位置爲0ui

// src/views/list/index.tsx
import * as React from 'react';
import { withRouter, RouteComponentProps } from 'react-router';
import styles from './list.scss';

const { useState, useEffect } = React;

interface IProps extends RouteComponentProps {
  [prop: string]: any
}
export interface IListItem {
  id: number,
  text: string
}

const arr: IListItem[] = [
  { id: 1, text: 'list1skdjfnsdnfsdnfsdf' },
  { id: 2, text: 'list2jilkfsjjfnsdnfsdf' },
  { id: 3, text: 'list3sudfjnfnfnffffsdf' },
  { id: 4, text: 'list4kl.mlmjjjfsdnfsdf' },
  { id: 5, text: 'list5ldskfoiquqiquwwww' },
  { id: 6, text: 'list6skdjfnsdnfsdnfsdf' },
  { id: 7, text: 'list7jufhfbvbvvvvaaadf' },
  { id: 8, text: 'list8,lkoqpoqwkeqlwele' }
];

let scrollTop: number = 0;

// list
function List(props: IProps) {
  const [list, setList] = useState([{ id: 1, text: '' }]);

  useEffect(() => {
    setList(arr);
    window.addEventListener('scroll', onScroll);

    return () => {
      window.removeEventListener('scroll', onScroll);
    }
  }, []);

  // 監聽列表與詳情的切換
  useEffect(() => {
    if (props.location.pathname.includes("/list/detail/") ) {
      // console.log('scrollTop -- detail: ', scrollTop);
      document.documentElement.scrollTop = 0;

    } else {
      window.addEventListener('scroll', onScroll);
      setTimeout(() => {
        // console.log('scrollTop -- list: ', scrollTop);
        document.documentElement.scrollTop = scrollTop;
      }, 0);
    }
  }, [props.location.pathname]);

  // 監聽滾動
  function onScroll() {
    // location.pathname 由於是同一組件,因此有問題,因此用原生js的
    if (location.hash.includes("/list/detail/") ) {
      window.removeEventListener('scroll', onScroll);
      
    } else {
      scrollTop = document.documentElement.scrollTop;
    }
  }

  function toDetail(id: number) {
    props.history.push(`/list/detail/${id}`);
  }

  return (
    <div className={styles.list}> <section className="list-content" style={{ display: props.location.pathname.includes("/list/detail/") ? 'none' : 'block' }} > { list.map((item, index) => { return ( <div key={index} className={styles['list-item']} onClick={() => toDetail(item.id)} > { item.text } </div> ) }) } </section> {/* detial */} { props.children } </div>
  )
}

export default withRouter(List);
複製代碼

最後

應該有其餘實現方法,本文也只是「僞實現」。。。spa

相關文章
相關標籤/搜索