Created
April 28, 2022 09:58
-
-
Save lejonmanen/5984ba0ee34cdf3a12fdfae83bb1921a to your computer and use it in GitHub Desktop.
Modifying an array with immer and TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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