Skip to content

Instantly share code, notes, and snippets.

@a1300
Created June 1, 2025 15:15
Show Gist options
  • Save a1300/eeb5b3978b444f9819e269263a416d0c to your computer and use it in GitHub Desktop.
Save a1300/eeb5b3978b444f9819e269263a416d0c to your computer and use it in GitHub Desktop.
svg
@a1300
Copy link
Author

a1300 commented Jul 12, 2025

use ref for performance gains:

https://www.youtube.com/watch?v=TgpTG5XYoz4

@a1300
Copy link
Author

a1300 commented Jul 12, 2025

Great question! To efficiently sync a user's interests (stored as a JS array) with your Drizzle/Postgres backend when they update their interests via a mutation, you should:

1. Data Model

Assume:

  • persons table (id, name, ...)
  • interests table (id, name)
  • person_interests table (person_id, interest_id) — many-to-many relationship

2. Frontend Flow

  • User sends the full, updated array of interests (e.g. ["music", "coding", "cooking"]) when they save.

3. Backend Mutation Steps

a. Upsert interests

  • For each interest in the array, ensure it exists in the interests table.
    • Use Drizzle’s insert with onConflictDoNothing (or similar) to avoid duplicates.

b. Fetch Interest IDs

  • Retrieve all interest IDs for the submitted names.

c. Sync Person's Interests

  • Fetch the current interests for the person from person_interests.
  • Compute:
    • To Add: Interests in the new array but not in DB.
    • To Remove: Interests in DB but not in the new array.
  • Use Drizzle to insert new links and delete old ones.

Sample Drizzle Code

// 1. Upsert interests
await db.insert(interests).values(
  newInterests.map(name => ({ name }))
).onConflictDoNothing(); // prevents duplicate interest names

// 2. Get interest IDs
const interestRecords = await db
  .select({ id: interests.id, name: interests.name })
  .from(interests)
  .where(in(interests.name, newInterests));

const interestIdMap = Object.fromEntries(
  interestRecords.map(rec => [rec.name, rec.id])
);

// 3. Get current user's interests
const currentLinks = await db
  .select({ interest_id: person_interests.interest_id })
  .from(person_interests)
  .where(eq(person_interests.person_id, personId));

const currentInterestIds = new Set(currentLinks.map(l => l.interest_id));
const newInterestIds = new Set(Object.values(interestIdMap));

// 4. Compute changes
const toAdd = [...newInterestIds].filter(id => !currentInterestIds.has(id));
const toRemove = [...currentInterestIds].filter(id => !newInterestIds.has(id));

// 5. Add new links
if (toAdd.length > 0) {
  await db.insert(person_interests).values(
    toAdd.map(interest_id => ({
      person_id: personId,
      interest_id,
    }))
  );
}

// 6. Remove old links
if (toRemove.length > 0) {
  await db.delete(person_interests)
    .where(
      and(
        eq(person_interests.person_id, personId),
        in(person_interests.interest_id, toRemove)
      )
    );
}

Why this approach?

  • Efficient: Only adds/removes what's changed.
  • Prevents duplicates.
  • Handles many-to-many properly.
  • Works with Drizzle and Postgres.

Tips

  • Wrap in a transaction for atomicity.
  • Validate input on the backend.
  • You do not update interests themselves, just the linking table.

If your interests are not a separate table (i.e., you store them as a JSON array), the approach is simpler (just update the array), but you'll lose normalization, searchability, and de-duplication features.

Let me know if you want the code adapted for a different schema or want transaction handling!

@a1300
Copy link
Author

a1300 commented Jul 13, 2025

@a1300
Copy link
Author

a1300 commented Jul 18, 2025

@a1300
Copy link
Author

a1300 commented Jul 18, 2025

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

To type a generic ReactNode that guarantees a className prop, you’ll want to constrain the type to a React element that accepts props — particularly one that includes className. A plain ReactNode is too flexible (it can be a string, fragment, boolean, etc.), so you’ll need a more refined approach.

Here’s a pattern that works well:

import React, { ReactElement, ComponentType } from 'react';

type WithClassNameProps = {
  className?: string;
};

type Props<T extends ComponentType<WithClassNameProps>> = {
  Component: T;
};

// Example usage
const Wrapper = <T extends ComponentType<WithClassNameProps>>({
  Component,
}: Props<T>) => {
  return <Component className="my-class" />;
};

🔍 What’s happening here:

  • ComponentType<P> is a generic for a React component that accepts props of type P.
  • We're restricting it with WithClassNameProps so we know for sure it accepts className.
  • This ensures your passed-in Component (like a div, button, or custom component) will support the className prop at type level.

If you’re passing an actual element (like <div />) rather than a component reference, you’d use ReactElement<WithClassNameProps> instead.

Would you like an example with JSX-style children too? Or maybe you want to extend the prop checks even further?

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

React.cloneElement is a powerful—but often misunderstood—tool in React’s arsenal. It lets you create a new React element based on an existing one, while overriding or adding props and children. Here's why and when you'd use it:

🧩 Why Use React.cloneElement()

  • Inject props into children: Useful when a parent component needs to modify or extend its children without changing their original implementation.
  • Enhance reusability: You can build flexible, reusable UI components by dynamically customizing child elements.
  • Avoid prop drilling: Instead of passing props through multiple layers, cloneElement lets you inject them directly.

📦 Common Use Cases

  • Customizing child components:

    const cloned = React.cloneElement(<Button />, { color: 'red' });

    This creates a new <Button /> with the color prop set to 'red'.

  • Dynamic rendering in lists:

    React.Children.map(children, (child, index) =>
      React.cloneElement(child, { isActive: index === selectedIndex })
    );

    This is handy for components like tabs or selectable lists.

  • Wrapping components with additional behavior:
    For example, adding event handlers or styling to children passed into a container.

⚠️ Caveats

  • Can make code harder to trace: Since props are injected dynamically, it’s not always obvious where they come from.
  • Not ideal for static typing: TypeScript may struggle with inferred props when using cloneElement.
  • Better alternatives often exist: Consider using render props, context, or custom hooks for clearer data flow.

Would you like to see a real-world example or explore alternatives like render props or context?

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

@a1300
Copy link
Author

a1300 commented Jul 19, 2025

@a1300
Copy link
Author

a1300 commented Jul 20, 2025

@a1300
Copy link
Author

a1300 commented Aug 2, 2025

``
const [selection, setSelection] = useState({ state: {}, items: [] });

const table = useReactTable({
data,
columns,
getRowId: row => row.id,
state: { rowSelection: selection.state },
onRowSelectionChange: updater => {
const newState = updater(selection.state);
const selectedItems = data.filter(item => newState[item.id]);
setSelection({ state: newState, items: selectedItems });
},
});

@a1300
Copy link
Author

a1300 commented Aug 4, 2025

@a1300
Copy link
Author

a1300 commented Sep 7, 2025

@a1300
Copy link
Author

a1300 commented Sep 11, 2025

type OnlyArrays<T> = {
    [K in keyof T]: T[K] extends any[] ? K : never
}[keyof T]

type ArrayItemType<T> = T extends (infer U)[] ? U : never;

function access<
    T extends object,
    K extends OnlyArrays<T>,
    A extends (a: ArrayItemType<T[K]>) => boolean
>
    (first: T, key: K, func: A): {
        added: Array<ArrayItemType<T[K]>>
         
    } {
        const added = (first[key] as Array<ArrayItemType<T[K]>>).filter(func)

        return {
            added,
        }
}

access(obj, "addresses", (a) => true);

improvement

function access<
  T extends Record<K, any[]>,
  K extends keyof T,
  A extends (a: ArrayItemType<T[K]>) => boolean
>(
  first: T,
  key: K,
  func: A
): {
  added: ArrayItemType<T[K]>[]
} {
  const added = first[key].filter(func);
  return { added };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment