Skip to content

Consider using createPortal instead of createRoot #4

@uzegonemad

Description

@uzegonemad

In React apps, it is a common practice to have context providers for things like theming components, setting up data fetching, etc.

Currently, slots are rendered using createRoot which creates a completely separate tree without access to an app's providers. This means that when rendering the component in DataTables, it may be unstyled, or may not have access to making API calls, etc.

createPortal solves this problem by rendering the element in a different physical location but retaining it in React's internal tree.

(I started working on a PR for this but couldn't immediately test the slot caching, so decided to toss it in an issue for now. I'll try to come back to it as time allows but if someone else beats me to this, that's fine too.)

A quick example when using Tanstack Query:

function ToggleFlaggedButton({ reportId, entryId, isFlagged }) {
    const { mutateAsync } = useMutation({
        mutationFn: async () => {
            const response = await fetch('/api/toggle-flagged', {
                method: 'POST',
                body: JSON.stringify({ reportId, entryId }),
                headers: { 'Content-Type': 'application/json' },
            });
            if (!response.ok) {
                throw new Error('Something went wrong.');
            }
            return await response.json();
        }
    });

    const onClick = () => {
        const action = mutateAsync({isFlagged: !isFlagged});

        toast.promise(action, {
            loading: 'Toggling flagged...',
            success: `The entry is now ${!isFlagged ? 'flagged' : 'unflagged'}.`,
            error: 'There was an error toggling the flagged status.'
        });
    }

    return (
        <div onClick={onClick} className={'inline-block cursor-pointer'} title={isFlagged ? 'Unflag Entry' : 'Flag Entry'}>{isFlagged ? <FaFlag/> : <FaRegFlag/>}</div>
    )
}

Table slot usage:

const slots = {
    // Flagged
    1: (data, row) => {
        return <ToggleFlaggedButton reportId={reportId} entryId={row.id} isFlagged={data} />
    },
];

<DataTable slots={slots} ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions