Skip to content

Usage within FlashList? #900

@subvertallchris

Description

@subvertallchris

Hi, thanks for building this, it fills an important need for us! I'm opening this as a new issue but having typed it up, it might be more of a feature request. Gonna leave it as is because it's both a request for advice and a proposal for an update.

I'm trying to this library within an existing FlashList and running into trouble because one should not embed a FlatList in an existing virtualized list. It appears I can copy/paste the list setup logic in Markdown.tsx to configure and feed elements into an existing List since there's a lot of overlapping logic. If that's the case, there might be a good opportunity to refactor so the core rendering logic is exposed in a hook and any list can consume it:

// Code copied/pasted from Markdown.tsx into a new hook
export function useMarkdownListData({ value, baseUrl, renderer, tokenizer }: MarkdownProps) {
  const colorScheme = useColorScheme();

  const rnElements = useMarkdown(value, {
    theme,
    baseUrl,
    renderer,
    colorScheme,
    styles,
    tokenizer,
  });

  const renderItem = useCallback(({ item }: { item: ReactNode }) => {
    return item as ReactElement;
  }, []);

  const keyExtractor = useCallback((_: ReactNode, index: number) => index.toString(), []);

  return { keyExtractor, renderItem, rnElements };
}

In my case, I used a custom hook with that code and then passed the data straight into my list. Here are relevant portions simplified.

// in the body
  const { keyExtractor, renderItem, rnElements } = useMarkdownListData({
    value: serverAlbum.notesMarkdown || '',
  });

  const listData = useMemo((): ListItem[] => {
    return [
      { type: 'header' as const, data: () => HeaderComponent },
      { type: 'controls' as const, data: () => ControlsComponent },
      { type: 'footer' as const, data: () => FooterComponent },
      ...rnElements.map((element) => ({ type: 'markdown' as const, data: element })), // <----- the one we care about here
    ];
  }, [HeaderComponent, FooterComponent, ControlsComponent]);

// Later on, FlashList props

            keyExtractor={(item, index) => {
              switch (item.type) {
                case 'header':
                case 'controls':
                case 'footer': {
                  return item.type;
                }
                case 'markdown': { // <------ the one we care about here
                  return keyExtractor(item.data, index);
                }
              }
            }}
            renderItem={({ item }) => {
              switch (item.type) {
                case 'header':
                case 'controls':
                case 'footer': {
                  return item.data();
                }
                case 'markdown': { // <------ the one we care about here
                  return renderItem({ item: item.data });
                }
              }
            }}

This will decouple the setup logic from the actual list presentation logic. It wouldn't change this library other than by exposing a hook that isolates the exact code you're already using, you'd just have to commit to exposing elements from your hook that are generic enough that others could use them.

Is this something you're open to? I can provide a PR.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions