vue-masonry-css
vue-masonry-css copied to clipboard
vue-masonry-css makes first components loaded unreactive
I'm facing a weird issue, the first components in the grid arent reactive anymore: see live
here is a previous production deployment , where everything works fine
🤔
Could there be a conflict with the lazy-load/fade-in image plugin your using? Maybe theres a way to tell that plugin of the updated positions. Is it just the images or are you seeing other events breaking?
Nice showcase by the way!
@paulcollett: thanks for the quick response
I'm glad you like it. I'm launching it tomorrow on Product Hunt :) I had to remove the grid feature in production unfortunately :(
Every events (@click...) and component methods (mounted()) are disabled for the first components. Here is the component where everything happen. Let me know if you find anything suspicious, or if you need more code to investigate.
I'm getting the exact same thing!
@tchret what did you end up using?
@mbarwick83 did my own grid 🤡
This seems reoccuring and something I'll look into.
@tchret Any tips on what you came up?
Same issue here. When using other vue components inside masonry they become unresponsive.
Hi there, just wanted to say the component is awesome and it's being incredibly useful and efficient with me. Unfortunately I also have this issue, trying to evoke a custom component @input event inside masonry. I'm also not sure of the best solution for so... Would there be any way to map any sort of event from masonry to it's child rendered components? Maybe using slots instead of creating the elements directly on template? I'm not sure. In any case, thanks for the simple solution!
I'm quite late to the party and initial link is down already, but while using infinite-loading + progressive-img everything works like a char. Maybe something to consider?
Hi,
I had such similar issue. I have an infinite wall, I add items in masonry depending on the scroll => no problem Sometimes I want to change all my data inside masonry => the data i changed, but the HTML of previously rendered components stays here
My workaround is to destroy masonry component before recreating it:
<masonry v-if="!killMasonry" :cols="5" :gutter="10">
<div v-for="item of itemList.slice(0, maxNumber)">
...
</div>
</masonry>
...
data: () => ({
maxNumber: 15,
killMasonry: false,
}),
props: {
itemList: Array
},
watch: {
'itemList': {
handler() {
this.killMasonry = true;
setTimeout(() => {
this.killMasonry = false;
}, 10);
}
}
},
...
In my opinion, that's an heavy bug :(
Have the same issue. Data changes in store do nor render to the screen. Kind of a deal braker for us ... Other than this, the plugin is very cool ... vote +1 for a fix ...
@wouterfovel and @thibaultbrocheton just use :key inside transition to force rerender of the component
<transition>
<masonry
:key="columnsCount"
:cols="{ default: columnsCount, 1000: 2, 500: 1}"
></masonry>
</transition>
Referenced from -> https://vuejs.org/v2/api/#key
@helariL
<masonry :cols="{default: 3, 1000: 2, 700: 1}">
<v-flex v-for="dimension in dimensions" :key="dimension.id">
... --- Code allowing a dimension.name to change ---
After we change a dimension's name, the db is updated and the vuex state mutates to these changes (state.dimensions mutates). The adapted (state.)dimension.name is not altered on screen when <masonry ...> is used. If we remove <masonry ...>, it works fine ... We are not adding new columns in our case ...
Same error here :( Actually all my components inside masonry are unresponsive. They trigger some stuff most of the time but the data doesn't update somehow... really weird
Same issue, nothing in this thread has worked :(. I have to run a refresh after I load all the items and it's a deal breaker.
We ran into the same issue and ended up using a Flexbox alternative, but first narrowed it down to a couple of problems:
- Any time the number of columns changes, contained elements lose reactivity
- When the component mounts, the
reCalculate
function is called twice: once with the default number of columns (2) and once with the number of columns you specified via props (in our case, 3). Since the number of columns has changed (2 -> 3), all contained elements lose reactivity.
Here's a simple Codepen demo illustrating the issues Elements in the 3-column layout are never reactive. Elements in the Responsive layout are only reactive in their default 2-column layout (try resizing the window).
The 2nd issue is also related to this check which returns early when previousWindowWidth
is the same as current window width.
Since reCalculate
is called twice with different column values, _reCalculateColumnCount
never gets called with the correct number of columns (3).
First recalculate:
-
displayColumns
is 2 -
previousWindowWidth
is undefined -
_reCalculateColumnCount
is called
Second recalculate:
-
displayColumns
is 3 -
previousWindowWidth
is the same as current window width -
_reCalculateColumnCount
is skipped
We were able to get around this by explicitly calling _reCalculateColumnCount
and setting previousWindowWidth
in the created
hook instead of/in addition to mounted
. This lets elements keep their reactivity as long as the number of columns is the same as when the component mounted.
As for the 1st issue, we think it has something to do with how Vue tracks key
(maybe it's losing internal references to elements) but we switched gears before debugging any further.
Hope that helps.
Wrap all child components in a div
. ie:
<masonry>
<div>
<some-component>
</div>
</masonry>
Wrap all child components in a
div
. ie:<masonry> <div> <some-component> </div> </masonry>
That doesn't help. In @sbine codepen the components are already wrapped in div
Am also facing this problem, which is a deal-breaker :(
Inspecting with Vue DevTools shows an inconsistency with the DOM once the column counts are changed. For instance, something simple like a loading
data property while false
in Vue DevTools is effectively true
on screen.
I also am having this issue which is a real bummer because I really like this solution otherwise.
@paulcollett you think you can find a solution?
Hello everyone. So I think I found a solution to this problem for myself anyways. I had a pretty typical use case that is something like this:
<masonry :cols="{default: 2, 700: 1}" :gutter="30">
<span v-for="number in [1,2,3,4,5,6,7]" :key="number">
<basic-card />
</span>
</masonry>
in my card component on re-size to 700px I would lose all my reactivity like everyone here. I read through @paulcollett 's script and saw that he was only grabbing the initial slot element for rerendering and had a sneaking suspicion that his script or Vue's render() function or something only cared about the initial child elements functionality, in this case that span tag. So I did an experiment like this:
<masonry :cols="{default: 2, 700: 1}" :gutter="30">
<basic-card/>
<basic-card/>
<basic-card/>
<basic-card/>
</masonry>
And sure enough on re-size my components kept their reactivity. SO, having done some work with Angular I wondered if there was some way to create that loop without nesting in another element like with ng-template and sure enough there is. You can nest template elements. So I tried something like this:
<masonry :cols="{default: 2, 700: 1}" :gutter="30">
<template v-for="number in [1,2,3,4,5,6,7]">
<basic-card :key="number"/>
</template>
</masonry>
and sure enough, everything seems to be working! Hope this helps.
@tcober Seems like a useful workaround, however I'm also using a draggable component to my implementation, which means I can't get the required root-level structure :(
I'm having issues when I wrap the elements in
