Repository: strapi/strapi
File: packages/core/content-manager/admin/src/pages/ListView/ListViewPage.tsx (TypeScript)

Code before:

  /**
   * If the persistent displayedHeaders are not yet initialized, set them to list.layout
   */
  React.useEffect(() => {
    // wait for list.layout to be loaded
    if (list.layout.length === 0) {
      return;
    }

    if (displayedHeaders.length === 0) {
      setDisplayedHeaders(list.layout);
    }
  }, [list.layout]);

  React.useEffect(() => {
    if (!schema?.attributes) return;
    if (displayedHeaders.length === 0) return;
    if (schema.uid !== model) return;

    const allowedDisplayHeaders = displayedHeaders.filter((header) =>
      Object.keys(schema?.attributes).includes(header.name)
    );

    if (allowedDisplayHeaders.length !== displayedHeaders.length) {
      setDisplayedHeaders(allowedDisplayHeaders);
    }
  }, [displayedHeaders]);

  const handleSetHeaders = (headers: string[]) => {
    setDisplayedHeaders(
      convertListLayoutToFieldLayouts(headers, schema!.attributes, list.metadatas)
    );
  };

  const [{ query }] = useQueryParams<{
    plugins?: Record<string, unknown>;
    page?: string;
    pageSize?: string;
    sort?: string;
  }>({
    page: '1',
    pageSize: list.settings.pageSize.toString(),
    sort: list.settings.defaultSortBy
      ? `${list.settings.defaultSortBy}:${list.settings.defaultSortOrder}`
      : '',
  });

  const params = React.useMemo(() => buildValidParams(query), [query]);

  const { data, error, isFetching } = useGetAllDocumentsQuery({

Review comment (suggestion):
Seems like you are saving the whole attribute array which could be simplified by only saving the attribute names you only need. For each collection type, we would like to save an ordered array of attribute names such as `["id", "name", "description", "created_at"]`.

Here is an example of what you are saving in the localstorage ⬇️  (searchable, label, sortable and attribute object are useless for this feature)
<img width="655" height="757" alt="Screenshot 2025-10-15 at 17 50 44" src="https://github.com/user-attachments/assets/959aea83-06e1-4850-b3bf-22630cf1dd1e" />


Code after:
  );

  const mapDisplayedHeaders = (headers: ListFieldLayout[]) => headers.map((header) => header.name);

  const displayedHeaders: ListFieldLayout[] = React.useMemo(() => {
    if (
      !displayedHeaderNames ||
      !list.metadatas ||
      Object.keys(list.metadatas).length <= 0 ||
      !schema?.attributes
    )
      return [];

    return convertListLayoutToFieldLayouts(displayedHeaderNames, schema.attributes, list.metadatas);
  }, [displayedHeaderNames, schema, list]);

  const handleSetHeaders = (headers: string[]) => {
    setDisplayedHeaderNames(headers);
  };

  const handleResetHeaders = () => {
    setDisplayedHeaderNames(mapDisplayedHeaders(list.layout));
  };

  /**
   * If the persistent displayedHeaders are not yet initialized, set them to list.layout
   */
  React.useEffect(() => {
    // wait for list.layout to be loaded
    if (list.layout.length === 0) {
      return;
    }

    if (!displayedHeaderNames) {
      handleResetHeaders();
    }
  }, [list.layout]);

  React.useEffect(() => {
    if (!schema?.attributes) return;
    if (!displayedHeaderNames || displayedHeaderNames.length === 0) return;
    if (schema.uid !== model) return;

    const allowedDisplayHeaders = displayedHeaderNames.filter((header) =>
      Object.keys(schema?.attributes).includes(header)
    );

    if (allowedDisplayHeaders.length !== displayedHeaderNames.length) {
      handleSetHeaders(allowedDisplayHeaders);
    }
  }, [displayedHeaderNames]);