naver / egjs-infinitegrid

A module used to arrange card elements including content infinitely on a grid layout.
https://naver.github.io/egjs-infinitegrid/
MIT License
2.23k stars 95 forks source link

keep-alive influence @egjs/vue-infinitegrid #434

Closed SageSanyue closed 3 years ago

SageSanyue commented 3 years ago

Description

Excuse me, but I'd like to ask how to restore scroll position with keepAlive?

Steps to check or reproduce

my codes like this: router:

{
   path: '/a',
   name: 'a,
   props: true,
   meta: {
     title: 'a-Page',
     keepAlive: true,
   },
   component: () => import('@/.../a'),
},
...
export default new Router({
  mode: 'history',
  scrollBehavior (to, from, savedPosition) {
    if (savedPosition && to.meta.keepAlive) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          window.scrollTo({
            top: savedPosition.y,
            left: 0,
          });
        }, 0);
      });
    }
  },
});

app.vue

<template>
  <div id="app" class="wrap">
    <keep-alive max="1">
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
      <router-view v-if="!$route.meta.keepAlive"></router-view>
  </div>
</template>

a.vue

<template>
   <masonry-infinite-grid
        ref="ig"
        id="masonry"
        class="container"
        v-bind:gap="-1"
        v-on:request-append="onRequestAppend"
    >
        <div 
            class="list_item" 
            v-for="(item, index) in items" 
            :key="index"
            :data-grid-groupkey="item.groupKey"
        >
        egjs {{ item.key }}
        <a href="/b/id">
            <img
                width="200"
                height="200"
                v-bind:src="
                    'https://naver.github.io/egjs-infinitegrid/assets/image/' +
                    ((item.key % 33) + 1) +
                    '.jpg'
                "
                alt="egjs" 
            />
        </a>
        </div>
    </masonry-infinite-grid>
</template>
<script>
import { MasonryInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
...
  components: { MasonryInfiniteGrid, }
  data() {
    return {
      items: [],
      status: null
    }
  },
  activated() {
    // can't catch '$refs.ig'
    this.$refs.ig.setStatus(this.status) // I want use old data in 'keepl-alive'
  },
  deactivated () {
    this.status = this.$refs.ig.getStatus();
  },
  methods: {
    getItems(nextGroupKey, count) {
        const nextItems = [];
        for (let i = 0; i < count; ++i) {
            const nextKey = nextGroupKey * count + i;
            nextItems.push({ groupKey: nextGroupKey, key: nextKey });
        }
        console.log('nextItems', nextItems)
        return nextItems;
    },
    onRequestAppend(e) {
        console.log('e', e)
        const nextGroupKey = (e.groupKey || -1) + 1;
        this.items = [...this.items, ...this.getItems(nextGroupKey, 10)];    },
  }
}
<script>

But when I return page it has error like:

[Vue warn]: Error in activated hook: "TypeError: Cannot read properties of undefined (reading 'setStatus')

What should I do? Please help.🤕 In fact, the 'items' in v-for="(item, index) in items" must use data which was stored in keepAlive. Because as requirement I have to use a button to fetch data of next page instead of 'onRequestAppend'.

daybrush commented 3 years ago

@SageSanyue

Hi. We will investigate this issue.

I think I should check a few things before that.

  1. Does activation occur before mounted?
  2. If keep-alive works, does mounted hook occur?
  3. If mounted occurs, it would be ok to write <masonry-infinite-grid :status="status"> code.
SageSanyue commented 3 years ago

@daybrush Thanks for your reply.

After using KeepAlive, the components that are wrapped in KeepAlive are cached the first time they are rendered, and the corresponding vnode and DOM are retrieved directly from the cache the next time they are rendered again.

  1. If keep-alive works, does mounted hook occur? the 'mounted' hook doesn't occur. Only 'activated' hook will occur. I don't know how to activate it. 😭
daybrush commented 3 years ago

@SageSanyue

Cannot read properties of undefined (reading 'setStatus') is occur when first rendering

if (this.$refs.ig && this.status) {
}

And use requestAnimationFrame

if (this.$refs.ig && this.status) {
    requestAnimationFrame(() => {
        this.$refs.ig.setStatus(this.status);
    });
}
SageSanyue commented 3 years ago

Sorry, it's maybe my fault. I created a demo using 'keep-alive' run well with '@egjs/vue-infinitegrid'. I'll find the fail reason of the real requirement.

SageSanyue commented 3 years ago

The reson of my fault is not 'keep-alive' but the following 2 reasons. 1.css-'overflow-x: hidden;'. I delete 'overflow-x: hidden;'

2.src/mixins/loadingMixin.js I delete the 'computed'. Before:

const loadingMixin = {
  computed: {
    isLoading: {
      get() {
        ...
      },
      set(flag) {
        ...
      },
    },
  },
  created() {
    this.isLoading = true;
  },
};
export default loadingMixin;

After:

const loadingMixin = {
  data() {
    return {
      isLoading: false
    }
  },
  created() {
    this.isLoading = true;
  },
};

export default loadingMixin;

Other files: index.vue

<div class="home">
  <AppMain />
</div>
...
.home {
position: relative;
  min-height: 100%;
  // overflow-x: hidden;
  background-color: #fbfbfb;}

AppMain.vue

<template>
  <ContainerWrapper>
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive"></router-view>
    </keep-alive>
      <router-view v-if="!$route.meta.keepAlive"></router-view>
  </ContainerWrapper>
</template>

a.vue (no need of 'getStatus', keepAlive can recognize posion)

<template>
   <masonry-infinite-grid
        ref="ig"
        id="masonry"
        class="container"
        v-bind:gap="-1"
        v-on:request-append="onRequestAppend"
    >
        <div 
            class="list_item" 
            v-for="(item, index) in items" 
            :key="index"
            :data-grid-groupkey="item.groupKey"
        >
        egjs {{ item.key }}
        <a href="/b/id">
            <img
                width="200"
                height="200"
                v-bind:src="
                    'https://naver.github.io/egjs-infinitegrid/assets/image/' +
                    ((item.key % 33) + 1) +
                    '.jpg'
                "
                alt="egjs" 
            />
        </a>
        </div>
    </masonry-infinite-grid>
</template>
<script>
import { MasonryInfiniteGrid } from "@egjs/vue-infinitegrid";
export default {
...
  components: { MasonryInfiniteGrid, }
  data() {
    return {
      items: [],
      status: null
    }
  },
  methods: {
    ...
}
<script>