Skip to content
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

[Masonry] Flickering After Updated Data Source #38419

Closed
2 tasks done
JiahaoZhu11 opened this issue Aug 11, 2023 · 2 comments
Closed
2 tasks done

[Masonry] Flickering After Updated Data Source #38419

JiahaoZhu11 opened this issue Aug 11, 2023 · 2 comments
Assignees
Labels
component: masonry This is the name of the generic UI component, not the React module! duplicate This issue or pull request already exists

Comments

@JiahaoZhu11
Copy link

JiahaoZhu11 commented Aug 11, 2023

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Steps to reproduce 🕹

Link to live example: https://codesandbox.io/s/testmasonry-qvq465?file=/Demo.tsx

Steps:

  1. Go to the example provided above to see the current behavior.

  2. Create a new example:
    2.1. Go to https://mui.com/material-ui/react-masonry/
    2.2. Click on "Edit in CodeSandbox" to open a CodeSandbox with the installed environment of the latest dependancies.
    2.3. Paste the following code, which is mimicking a "load more" action in a real-would scenario.

import * as React from "react";
import Box from "@mui/material/Box";
import { styled } from "@mui/material/styles";
import Paper from "@mui/material/Paper";
import Masonry from "@mui/lab/Masonry";

const heights = [150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80];

const templates = [...heights, ...heights, ...heights, ...heights];

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: theme.palette.mode === "dark" ? "#1A2027" : "#fff",
  ...theme.typography.body2,
  padding: theme.spacing(0.5),
  textAlign: "center",
  color: theme.palette.text.secondary
}));

const ItemWrapper = (props: { index: number; height: number }): JSX.Element => {
  return <Item sx={{ height: props.height }}>{props.index + 1}</Item>;
};

const ItemMemo = React.memo(
  ItemWrapper,
  (prevProps, nextProps) => prevProps.height === nextProps.height
);

export default function BasicMasonry() {
  const [heights, setHeights] = React.useState(templates.slice(0, 30));

  setTimeout(() => setHeights(templates.slice(0, 60)), 3000);

  return (
    <Box sx={{ width: 500, minHeight: 393 }}>
      <Masonry columns={4} spacing={2}>
        {heights.map((height, index) => (
          <ItemMemo key={index} index={index} height={height} />
        ))}
      </Masonry>
    </Box>
  );
}

Current behavior 😯

Generally speaking, it seems like any update of the source data will cause a flicker of the entire masonry, as shown below.

record_1

I do understand each update will cause an unavoidable recalculation for the entire layout, but my current demand is a "load more" action, so ideally, the displayed ones should be kept as they are.

At first, I thought it was caused by a re-rendering of each cell, thus I tried to wrap each of the cells with React.memo to manage the re-rendering, but it didn't work.

Then, by closely looking at the behavior, I found out that at the very first render, the newly added cells will appear on the left side, which pushes the previously displayed ones to the right, as shown below.

record_2

The key frame is frame 192 as shown here:

record_2_cut

This is a quite weird behavior to me, I don't know how it is implemented under the hood, but there should be a way to avoid the flicker by that. It seems like the problem isn't caused by the re-rendering of the cells, instead, it is caused by the re-arrangement of the layout. Again, since the position of the previously displayed cells is not moved at all, even though they might be placed again at update, the action should be insensible to the user, because those cells are not re-rendered due to the use of React.memo.

Expected behavior 🤔

The expected behavior is to visually not flicker the previously displayed cells and only append the new ones starting from the end of them.

Context 🔦

I need to implement a "load more" action which is triggered when the bottom of the masonry has been reached. With my data structure and logic design, I have the ratios of the cells in my data, so I can calculate both the width and height for each cell before rendering.

Your environment 🌎

This problem is not environment-related, so a CodeSandbox sample should be enough.

@JiahaoZhu11 JiahaoZhu11 added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Aug 11, 2023
@zannager zannager added the component: masonry This is the name of the generic UI component, not the React module! label Aug 11, 2023
@DiegoAndai
Copy link
Member

DiegoAndai commented Aug 11, 2023

Hey @JiahaoZhu11, I think this is the same as #36673, right? We're currently working on a fix for that issue

@DiegoAndai
Copy link
Member

Closing as duplicate of #36673. Feel free to reopen if it's not actually a duplicate

@DiegoAndai DiegoAndai closed this as not planned Won't fix, can't repro, duplicate, stale Aug 15, 2023
@DiegoAndai DiegoAndai added duplicate This issue or pull request already exists and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Aug 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: masonry This is the name of the generic UI component, not the React module! duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

3 participants