-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue when removing item #12
Comments
This is the expected behavior, though I need to it document it better. This is the same problem solved by:
When you change your items list you are responsible for resetting the positioner. The reason for this is Masonic can't make assumptions about changes to the items array, since people could be using a list this mutable or immutable, that gets longer over time, etc. |
I should maybe throw a specific error in dev, too, if the items list gets shorter but the positioner doesn't change. Will have to explore that. |
Should it work with the useMasonry() hook too? |
@renanbgarcia Numerous problems in your example, but at the end of the day it's just not a good idea to do this. It's rather out of the scope of the library. Firstly, you're unlikely to get the kind of behavior you're looking for. No matter what, you're going to have to trigger a reflow on the entire grid, which means when a user deletes an item they'll end up back at the beginning of the grid each time it happens. You're much better off doing something else with the card when it's been deleted like inserting a placeholder letting a user know it was deleted. The primary objective of this library is to create masonry grids in an algorithmically-sound way. A secondary objective is keeping the hit to the bundle size low. Neither of those two things really mesh with this capability. There might be a day when I revisit this, but it's not on the current roadmap. |
In that case Line 42 in 6fca869
What happens now:
I think it's clear what will happen on 3 step if the items list becomes shorter. It should be something like that: type UsePositionerState = {
deps: React.DependencyList
positioner: Positioner
}
const [state, setState] = useState<UsePositionerState>(() => {
const positioner = initPositioner()
return {
deps,
positioner
}
})
let { deps: previousDeps, positioner } = state
const hasDepsChanged = !isEqual(previousDeps, deps)
if (hasDepsChanged) {
const newPositioner = initPositioner()
positioner = newPositioner
previousDeps = deps
setState({ deps, positioner })
} It will guarantee new positioner instance during the same render. |
@khmm12 Thanks again for the detailed look into the implementation. Would you want to submit a PR for this? Something like the above looks good for now. In the next major it'd be nice to drop deps and accept an |
@jaredLunde, @khmm12 I don't think the issue it completely fixed. I continue to see the issue even after upgrade to v3.3.10. |
@y0zhyk post a reproduction on codesandbox please |
I agree. it didn't fixed. |
@y0zhyk @JhonJohnatan Could you share an example? It's hard to say anything helpful without code. I have some assumptions, but it's better to see the example at first. |
@khmm12 @jaredLunde I've noticed the same issue even after updating to the latest version. I've forked the codesandbox example in the first post and updated Masonic to the latest version, but I receive the error
Screen.Recording.2021-05-17.at.10.44.39.PM.movHere's the forked codesandbox: https://codesandbox.io/s/masonic-example-forked-hcz62 |
@cryptoAlgorithm you can try the following thing: if(__to_be_removed__) return null not pretty, but works |
The same example but using masonic hooks directly. The key difference is const positioner = usePositioner(
{ width, columnGutter: 8, columnWidth: 172 },
[cats.length]
); You should tell positioner about collection size changes. May it makes sense to add @jaredLunde what do you think? |
@sebyx07 good suggestion, but I'm sure there'll be issues managing 10k+ items with a few thousand more deleted items... @khmm12 this solution seems to be promision. I'll impliment it when I have the time. I was using a hack previously to essentially reinitialise masonic every time the length of the data changes (yes, very inefficient) |
@khmm12 how would you solve this issue happening when a masonic <List /> is in use? |
@mattandersonfg in this case Personally I don't see any problem to use hooks directly or create your component using these hooks. P.S. I don't want to be "Devil's advocate". IMO |
@khmm12 I'm providing both a |
same problem |
Ugly But It Works™: Copy of https://github.com/jaredLunde/masonic/blob/main/src/masonry.tsx with additions: + // Workaround for https://github.com/jaredLunde/masonic/issues/12
+ const itemCounter = React.useRef<number>(props.items.length);
+ let shrunk = false;
+ if (props.items.length !== itemCounter.current) {
+ if (props.items.length < itemCounter.current) shrunk = true;
+ itemCounter.current = props.items.length;
+ }
+
- nextProps.positioner = usePositioner(nextProps);
+ nextProps.positioner = usePositioner(nextProps, [shrunk && Math.random()]); We only update on a smaller array because otherwise there is flicker (e.g. on more items coming in from infinite scroll). Make sure you |
Will post my quick workaround for Masonry component. After detecting an item remove I increment removesCount that goes to grid key and rerenders grid. const itemsCount = items?.length;
const prevItemsCount = usePrevious(itemsCount);
const removesCount = useRef(0);
const gridKeyPostfix = useMemo(() => {
if (!itemsCount || !prevItemsCount) return removesCount.current;
if (itemsCount < prevItemsCount) {
removesCount.current += 1;
return removesCount.current;
}
return removesCount.current;
}, [itemsCount, prevItemsCount]);
<Masonry
key={`${gridKey}-${gridKeyPostfix}`} |
This helped a lot. I was trying to get around with that flickering for a while. Thanks! |
@gadicc why do you need const lengthRef = useRef(0)
// ...
const positioner = usePositioner(
{ width, columnWidth, columnGutter },
[items.length < lengthRef.current]
)
// ...
lengthRef.current = items.length |
thanks so much, i fixed it |
Describe the bug
Hey Jared :) I found an issue when we remove element from the items list. If there is a lot of items, it seems to work. But if the list is small, we get an error.
To Reproduce
I made a sandbox to reproduce : https://codesandbox.io/s/masonic-example-lpe8s
Just click on the button "Remove a cat"
If you change the number of cat to 200 for example, it works.
With 20 cats, it failed with the following error:
The text was updated successfully, but these errors were encountered: