Skip to content

Instantly share code, notes, and snippets.

@lejonmanen
Created April 28, 2022 09:58
Show Gist options
  • Save lejonmanen/5984ba0ee34cdf3a12fdfae83bb1921a to your computer and use it in GitHub Desktop.
Save lejonmanen/5984ba0ee34cdf3a12fdfae83bb1921a to your computer and use it in GitHub Desktop.
Modifying an array with immer and TypeScript
import produce from 'immer'
import { useState } from 'react'
// Move the interface to a separate file, User.ts
interface User {
id: number;
name: string;
}
// Many times, a variable may not have received its value yet. Use the TypeScript union operator to make that clear. A common use case is when fetching data from an API.
type Maybe<T> = undefined | null | T;
// Example usage: let data: Maybe<User[]>;
const ManageUsers = () => {
const [users, setUsers] = useState<User[]>(getTestData())
const addUser = (): void => setUsers(produce(draft => {
const newUser = { name: 'Example', id: createId() }
draft.push(newUser)
}))
// Declare an alias for the function type to make the function definition cleaner. More useful if you use the type more than once.
type ChangeNameType = (a: number, b: string) => void;
const changeName: ChangeNameType = (userId, newName) => setUsers(produce(draft => {
const found: Maybe<User> = draft.find(user => user.id === userId)
if( found ) {
found.name = newName
}
}))
return (
<div>
<h1> Manage users </h1>
<h3> View and change user names </h3>
<ul>
{users.map(user => (
<UserItem key={user.id} user={user} setUserName={newName => changeName(user.id, newName)} />
))}
</ul>
<h3> Add a new user </h3>
<p>
<button onClick={addUser}> Add example user </button>
</p>
</div>
)
}
// These are the props UserItem expects to get
interface UserItemProps {
user: User;
setUserName: (newName: string) => void;
}
const UserItem = ({ user: { name }, setUserName }: UserItemProps) => {
const [newName, setNewName] = useState<string>(name)
return (
<li key={name}>
{name}
<input
type='text'
value={newName}
onChange={(event) => setNewName(event.target.value)}
/>
<button onClick={() => setUserName(newName)}>
Save
</button>
</li>
)
};
// Only used for testing
function getTestData(): User[] {
return ["Bono", "The Edge", "Adam Clayton", "Larry Mullen Jr"].map((name) => ({
name: name,
id: createId(),
}));
}
function createId() {
// Random number between 0-1000000. The chance of failure is one in a million
return Math.round(Math.random() * 1000000)
}
export default ManageUsers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment