101_react_tips_and_tricks
101_react_tips_and_tricks
All rights reserved. The author has taken care in preparation of this
book, but makes no expressed or implied warranty of any kind, and
assumes no responsibility for errors or omissions. No liability is
assumed for incidental or consequential damages in with or arising
out of the use of the information contained herein.
Thank you!
INTRODUCTION
In this article, I share the 101 best tips & tricks I learned
over the years.
TABLE OF CONTENTS
component
13. Use the CSS :empty pseudo-class to
hide elements with no children
14. Group all the state and context at the top
of the component
Category #2: Effective Design Patterns &
Techniques 🛠
15. Leverage the children props for cleaner
code (and performance benefits)
16. Build composable code with compound
components
17. Make your code more extensible with
render functions or component
functions props
18. When dealing with different cases, use
value === case && <Component /> to
avoid holding onto old state
19. Always use error boundaries
Category #3: Keys & Refs 🗝
20. Use crypto.randomUUID or
Math.random to generate keys
21. Make sure your list items IDs are stable
(i.e., they don't change between renders)
22. Strategically use the key attribute to
trigger component re-renders
23. Use a ref callback function for
tasks such as monitoring size changes and
managing multiple node elements.
Category #4: Organizing React code 🧩
24. Colocate React components with their
assets (e.g., styles, images, etc.)
25. Limit your component file size
issues
52. Leverage useDebugValue in your
custom hooks for better visibility in React
DevTools
53. Use the why-did-you-render library
to track component rendering and identify
potential performance bottlenecks
54. Hide logs during the second render in
Strict Mode
Category #8: Testing React code 🧪
55. Use React Testing Library to test
your React components effectively
56. React Testing Library: Use testing
playground to effortlessly create queries
57. Conduct end-to-end tests with Cypress
or Playwright
58. Use MSW to mock network requests in
your tests
Category #9: React hooks 🎣
59. Make sure you perform any required
cleanup in your useEffect hooks
60. Use refs for accessing DOM elements
61. Use refs to preserve values across re-
renders
62. Prefer named functions over arrow
functions within hooks such as useEffect
to easily find them in React Dev Tools
63. Encapsulate logic with custom hooks
64. Prefer functions over custom hooks
65. Prevent visual UI glitches by using the
useLayoutEffect hook
// ✅Good
<MyComponent/>
function Dashboard() {
return (
<div>
<Header />
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 12 / 140
<Main />
</div>
);
}
function Dashboard() {
return (
<Fragment>
<Header />
<Main />
</Fragment>
);
}
<>
<FirstChild />
<SecondChild />
</>;
>
{text ?? "Click here"}
</button>
);
}
✅ Good: You can set all your defaults in one place at the
top. This makes it easy for someone to locate them.
function Button({
onClick,
text = "Click here",
small = false,
colorScheme = "light",
}) {
return (
<button
onClick={onClick}
style={{
color: colorScheme === "dark" ?
"white" : "black",
fontSize: small ? "12px" : "16px",
}}
>
{text}
</button>
);
}
// ✅Good
<Button text="Click me" colorScheme="dark"
/>
/>
)}
</div>
);
}
let gradeSum = 0;
let gradeCount = 0;
grades.forEach((grade) => {
gradeCount++;
gradeSum += grade;
});
gradeSum += grade;
});
return gradeSum / gradeCount;
};
return (
<>
<h1>Class Registration Form</h1>
<form>
<label>
Name:{" "}
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 21 / 140
<input
type="text"
value={name}
onChange={(evt) =>
setFormState((formState) =>
({
...formState,
name: evt.target.value,
}))
}
/>
</label>
<label>
Email:{" "}
<input
type="email"
value={email}
onChange={(evt) =>
setFormState((formState) =>
({
...formState,
email: evt.target.value,
}))
}
/>
</label>
</form>
</>
);
}
✅ Good: Introduce
createFormValueChangeHandler that returns the
correct handler for each field.
function Form() {
const [{ name, email }, setFormState] =
useState({
name: "",
email: "",
});
const createFormValueChangeHandler =
(field) => {
return (event) => {
setFormState((formState) => ({
...formState,
[field]: event.target.value,
}));
};
};
return (
<>
<h1>Class Registration Form</h1>
<form>
<label>
Name:{" "}
<input
type="text"
value={name}
onChange=
{createFormValueChangeHandler("name")}
/>
</label>
<label>
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 23 / 140
Email:{" "}
<input
type="email"
value={email}
onChange=
{createFormValueChangeHandler("email")}
/>
</label>
</form>
</>
);
}
function CoursesSelector() {
const OPTIONS = ["Maths", "Literature",
"History"];
const renderOption = (option: string) =>
{
return <option>{option}</option>;
};
return (
<select>
{OPTIONS.map((opt) => (
<Fragment key={opt}>
{renderOption(opt)}</Fragment>
))}
</select>
);
}
function CoursesSelector() {
return (
<select>
{OPTIONS.map((opt) => (
<Fragment key={opt}>
{renderOption(opt)}</Fragment>
))}
</select>
);
}
function CoursesSelector() {
return (
<select>
{OPTIONS.map((opt) => (
<option key={opt}>{opt}</option>
))}
</select>
);
}
useState<Item | undefined>();
return (
<>
{selectedItem != null && <div>
{selectedItem.name}</div>}
<List
items={items}
selectedItem={selectedItem}
onSelectItem={setSelectedItem}
/>
</>
);
}
return (
<>
{selectedItem != null && <div>
{selectedItem.name}</div>}
<List
items={items}
selectedItemId={selectedItemId}
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 27 / 140
onSelectItem={setSelectedItemId}
/>
</>
);
}
}
// TODO: Do something
},
[user]
);
if (user == null) {
return null;
}
return (
<div>
{posts.map((post) => (
<button key={post.id} onClick={()
=> handlePostSelect(post.id)}>
{post.title}
</button>
))}
</div>
);
}
getUserPosts(user.id), [user.id]);
return (
<div>
{posts.map((post) => (
<button key={post.id} onClick={()
=> handlePostSelect(post.id)}>
{post.title}
</button>
))}
</div>
);
}
.posts-wrapper {
border: solid 1px red;
}
.posts-wrapper:empty {
display: none;
}
When all the state and context are located at the top, it
is easy to spot what can trigger a component re-render.
function App() {
const [email, setEmail] = useState("");
const onEmailChange = (event) => {
setEmail(event.target.value);
};
const [password, setPassword] =
useState("");
const onPasswordChange = (event) => {
setPassword(event.target.value);
};
const theme = useContext(ThemeContext);
return (
<div className={`App ${theme}`}>
<h1>Welcome</h1>
<p>
Email: <input type="email" value=
{email} onChange={onEmailChange} />
</p>
<p>
Password:{" "}
<input type="password" value=
{password} onChange={onPasswordChange} />
</p>
</div>
);
}
function App() {
const theme = useContext(ThemeContext);
const [email, setEmail] = useState("");
const [password, setPassword] =
useState("");
const onEmailChange = (event) => {
setEmail(event.target.value);
};
const onPasswordChange = (event) => {
setPassword(event.target.value);
};
return (
<div className={`App ${theme}`}>
<h1>Welcome</h1>
<p>
Email: <input type="email" value=
{email} onChange={onEmailChange} />
</p>
<p>
Password:{" "}
<input type="password" value=
{password} onChange={onPasswordChange} />
</p>
</div>
);
}
function App() {
// Some other logic…
return <Dashboard />;
}
function Dashboard() {
const [currentTime, setCurrentTime] =
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 34 / 140
useState(new Date());
useEffect(() => {
const intervalId = setInterval(() => {
setCurrentTime(new Date());
}, 1_000);
return () => clearInterval(intervalId);
}, []);
return (
<>
<h1>{currentTime.toTimeString()}</h1>
<MyVerySlowComponent /> {/* Renders
whenever `Dashboard` renders */}
</>
);
}
function App() {
return (
<Dashboard>
<MyVerySlowComponent />
</Dashboard>
);
}
return (
<>
<h1>{currentTime.toTimeString()}</h1>
{children}
</>
);
}
<Menu>
<MenuButton>
Actions <span aria-hidden>▾</span>
</MenuButton>
<MenuList>
<MenuItem onSelect={() =>
alert("Download")}>Download</MenuItem>
<MenuItem onSelect={() =>
alert("Copy")}>Create a Copy</MenuItem>
<MenuLink as="a"
href="https://reacttraining.com/workshops/"
>
Attend a Workshop
</MenuLink>
</MenuList>
</Menu>
🏖 https://codesandbox.io/p/sandbox/counter-
zrl9pf
function App() {
const [selectedType, setSelectedType] =
useState < ResourceType > "posts";
return (
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 38 / 140
<>
<Navbar selectedType={selectedType}
onSelectType={setSelectedType} />
{selectedType === "posts" &&
<Resource type="posts" />}
{selectedType === "snippets" &&
<Resource type="snippets" />}
</>
);
}
function App() {
const [quotes, setQuotes] = useState([]);
const [selectedQuoteId,
setSelectedQuoteId] = useState(undefined);
// Fetch quotes
useEffect(() => {
const loadQuotes = () =>
fetchQuotes().then((result) => {
setQuotes(result);
});
loadQuotes();
}, []);
return (
<List
items={quotesWithIds}
selectedItemId={selectedQuoteId}
onSelectItem={setSelectedQuoteId}
/>
);
}
return (
<List
items={quotes}
selectedItemId={selectedQuoteId}
onSelectItem={setSelectedQuoteId}
/>
);
}
🏖 Sandbox
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 43 / 140
useEffect(() => {
ref.current?.focus();
}, []);
function App() {
const ref = useCallback((inputNode) => {
inputNode?.focus();
}, []);
onPostSelect(post.id);
};
};
return (
<>
<h1>Posts</h1>
<ul>
{filteredPosts.map((post) => {
return (
<li key={post.id} onClick=
{createPostSelectHandler(post)}>
{post.title}
</li>
);
})}
</ul>
</>
);
}
{filteredPosts.map((post) => (
<li
key={post.id}
onClick=
{createPostSelectHandler(post)}
style={{ color: post.id ===
selectedPostId ? "red" : "black" }}
>
{post.title}
</li>
))}
</ul>
</>
);
}
useEffect(() => {
setFilteredPosts(filterPosts(posts,
filters));
}, [posts, filters]);
return (
<Dashboard>
<Filters filters={filters}
onFiltersChange={setFilters} />
{filteredPosts.length > 0 && <Posts
posts={filteredPosts} />}
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 52 / 140
</Dashboard>
);
}
return (
<Dashboard>
<Filters filters={filters}
onFiltersChange={setFilters} />
{filteredPosts.length > 0 && <Posts
posts={filteredPosts} />}
</Dashboard>
);
}
function App() {
const [sortOrder, setSortOrder] =
useState("popular");
return (
<div className="App">
<LeftSidebar />
<Main sortOrder={sortOrder}
setSortOrder={setSortOrder} />
<RightSidebar />
</div>
);
}
Latest
</Button>
</div>
);
}
function Main() {
const [sortOrder, setSortOrder] =
useState("popular");
return (
<div>
<Button
onClick={() =>
setSortOrder("popular")}
active={sortOrder === "popular"}
>
Popular
</Button>
<Button
onClick={() =>
setSortOrder("latest")}
active={sortOrder === "latest"}
>
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 55 / 140
Latest
</Button>
</div>
);
}
"latest"}
>
Latest
</Button>
</div>
);
}
function App() {
const [todos, setToDos] = useState([]);
const handleAddTodo = useCallback(
(todo) => {
setToDos([...todos, todo]);
},
[todos]
);
},
[todos]
);
return (
<div className="App">
<TodoInput onAddTodo={handleAddTodo}
/>
<TodoList todos={todos} onRemoveTodo=
{handleRemoveTodo} />
</div>
);
}
function App() {
const [todos, setToDos] = useState([]);
const handleAddTodo = useCallback((todo)
=> {
setToDos((prevTodos) => [...prevTodos,
todo]);
}, []);
return (
<div className="App">
<TodoInput onAddTodo={handleAddTodo}
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 59 / 140
/>
<TodoList todos={todos} onRemoveTodo=
{handleRemoveTodo} />
</div>
);
}
localStorage.getItem(THEME_LOCAL_STORAGE_KE
Y) || "dark"
);
localStorage.setItem(THEME_LOCAL_STORAGE_KE
Y, theme);
};
return (
<div
className="page-wrapper"
style={{ background: theme === "dark"
? "black" : "white" }}
>
<div className="header">
<button onClick={() =>
handleThemeChange("dark")}>Dark</button>
<button onClick={() =>
handleThemeChange("light")}>Light</button>
</div>
<div>{children}</div>
</div>
);
}
localStorage.setItem(THEME_LOCAL_STORAGE_KE
Y, theme);
};
return (
<div
className="page-wrapper"
style={{ background: theme === "dark"
? "black" : "white" }}
>
<div className="header">
<button onClick={() =>
handleThemeChange("dark")}>Dark</button>
<button onClick={() =>
handleThemeChange("light")}>Light</button>
</div>
<div>{children}</div>
</div>
);
}
🏖 https://codesandbox.io/p/sandbox/context-
split-vdny3w
function App() {
const [theme, setTheme] = useState(
() =>
localStorage.getItem(THEME_LOCAL_STORAGE_KE
Y) || DEFAULT_THEME
);
useEffect(() => {
if (theme !== "system") {
updateRootElementTheme(theme);
return;
}
? "dark"
: "light";
updateRootElementTheme(systemTheme);
const themeContextValue = {
theme,
setTheme: (theme) => {
localStorage.setItem(THEME_LOCAL_STORAGE_KE
Y, theme);
setTheme(theme);
},
};
return (
<div className="App">
<ThemeContext.Provider value=
{themeContextValue}>
<Dashboard
posts={posts}
onPostSelect={onPostSelect}
selectedPostId={selectedPostId}
/>
</ThemeContext.Provider>
</div>
);
}
function App() {
const [selectedPostId, setSelectedPostId]
= useState(undefined);
const onPostSelect = (postId) => {
// TODO: some logging
setSelectedPostId(postId);
};
return (
<div className="App">
<ThemeProvider>
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 66 / 140
<Dashboard
posts={posts}
onPostSelect={onPostSelect}
selectedPostId={selectedPostId}
/>
</ThemeProvider>
</div>
);
}
updateRootElementTheme(systemTheme);
const themeContextValue = {
theme,
setTheme: (theme) => {
localStorage.setItem(THEME_LOCAL_STORAGE_KE
Y, theme);
setTheme(theme);
},
};
return (
<div className="App">
<ThemeContext.Provider value=
{themeContextValue}>
{children}
</ThemeContext.Provider>
</div>
);
}
email: "",
password: "",
});
const onEmailChange = (event) => {
setState((prevState) => ({
...prevState, email: event.target.value
}));
};
const onPasswordChange = (event) => {
setState((prevState) => ({
...prevState, password: event.target.value
}));
};
return (
<div className="App">
<h1>Welcome</h1>
<p>
Email: <input type="email" value=
{email} onChange={onEmailChange} />
</p>
<p>
Password:{" "}
<input type="password" value=
{password} onChange={onPasswordChange} />
</p>
</div>
);
}
Example 👇
const ExpensiveList = memo(
({ posts }) => {
return <div>{JSON.stringify(posts)}
</div>;
},
(prevProps, nextProps) => {
// Only re-render if the last post or
the list size changes
const prevLastPost =
prevProps.posts[prevProps.posts.length -
1];
const nextLastPost =
nextProps.posts[nextProps.posts.length -
1];
return (
prevLastPost.id === nextLastPost.id
&&
prevProps.posts.length ===
nextProps.posts.length
);
}
);
});
function useTheme() {
const [theme, setTheme] =
useState("light");
useEffect(() => {
const dqMediaQuery =
window.matchMedia("(prefers-color-scheme:
dark)");
handleThemeChange(dqMediaQuery.matches
? "dark" : "light");
const listener = (event) => {
handleThemeChange(event.matches ?
"dark" : "light");
};
dqMediaQuery.addEventListener("change",
listener);
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 79 / 140
return () => {
dqMediaQuery.removeEventListener("change",
listener);
};
}, [handleThemeChange]);
return theme;
}
const handleThemeChange =
useCallback((newTheme) => {
pushLog(["Theme changed"], {
context: {
theme: newTheme,
},
});
setTheme(newTheme);
}, []);
function useLoadData(fetchData) {
const [result, setResult] = useState({
type: "notStarted",
});
function useLoadData(fetchData) {
const [result, setResult] = useState({
type: "notStarted",
});
Expensive to load.
Only relevant to some users (like premium
features).
Not immediately necessary for the initial user
interaction.
🏖 https://stackblitz.com/edit/vitejs-vite-czefdj?
file=src%2FApp.jsx
borderBottom:
index === items.length - 1 ?
"none" : "1px solid #ccc",
}}
>
<LogLine log={log} index={index}
/>
</div>
)}
/>
);
}
🏖 https://codesandbox.io/p/sandbox/strict-
mode-example-pyrcg8
function useCurrentTime() {
const [time, setTime] = useState(new
Date());
useEffect(() => {
const intervalId = setInterval(() => {
setTime(new Date());
}, 1_000);
return () => clearInterval(intervalId);
}, [setTime]);
return time;
}
useDebugValue(time);
🏖 https://codesandbox.io/p/sandbox/why-did-
you-render-sandbox-forked-nc4fnk
function Timer() {
const [time, setTime] = useState(new
Date());
useEffect(() => {
setInterval(() => {
setTime(new Date());
}, 1_000);
}, []);
function Timer() {
const [time, setTime] = useState(new
Date());
useEffect(() => {
const intervalId = setInterval(() => {
setTime(new Date());
}, 1_000);
// We clear the interval
return () => clearInterval(intervalId);
}, []);
You can use the useRef hook, like in the example below,
where we need access to the canvas element.
🏖 https://codesandbox.io/p/sandbox/chart-js-
example-xdrnqv
re-render.
function Timer() {
const [time, setTime] = useState(new
Date());
let intervalId;
useEffect(() => {
intervalId = setInterval(() => {
setTime(new Date());
}, 1_000);
return () => clearInterval(intervalId);
}, []);
return (
<>
<>Current time:
{time.toLocaleTimeString()} </>
<button onClick={stopTimer}>Stop
timer</button>
</>
);
}
function Timer() {
const [time, setTime] = useState(new
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 99 / 140
Date());
const intervalIdRef = useRef();
const intervalId = intervalIdRef.current;
useEffect(() => {
const interval = setInterval(() => {
setTime(new Date());
}, 1_000);
intervalIdRef.current = interval;
return () => clearInterval(interval);
}, []);
return (
<>
<>Current time:
{time.toLocaleTimeString()} </>
<button onClick={stopTimer}>Stop
timer</button>
</>
);
}
function HelloWorld() {
useEffect(() => {
console.log(" 🚀
~ Hello, I just got
mounted");
}, []);
It's better to extract the logic that returns the theme into
a custom hook (to reuse it and keep the component
clean).
useEffect(() => {
const dqMediaQuery =
window.matchMedia("(prefers-color-scheme:
dark)");
setTheme(dqMediaQuery.matches ? "dark"
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 102 / 140
: "light");
const listener = (event) => {
setTheme(event.matches ? "dark" :
"light");
};
dqMediaQuery.addEventListener("change",
listener);
return () => {
dqMediaQuery.removeEventListener("change",
listener);
};
}, []);
return (
<div className={`App ${theme === "dark"
? "dark" : ""}`}>Hello Word</div>
);
}
function App() {
const theme = useTheme();
return (
<div className={`App ${theme === "dark"
? "dark" : ""}`}>Hello Word</div>
);
}
useState("light");
useEffect(() => {
const dqMediaQuery =
window.matchMedia("(prefers-color-scheme:
dark)");
setTheme(dqMediaQuery.matches ? "dark"
: "light");
const listener = (event) => {
setTheme(event.matches ? "dark" :
"light");
};
dqMediaQuery.addEventListener("change",
listener);
return () => {
dqMediaQuery.removeEventListener("change",
listener);
};
}, []);
return theme;
}
In effect:
function App() {
const locale = useLocale();
return (
<div className="App">
<IntlProvider locale={locale}>
<BlogPost post={EXAMPLE_POST} />
</IntlProvider>
</div>
);
}
function useLocale() {
return window.navigator.languages?.[0] ??
window.navigator.language;
}
<IntlProvider locale={locale}>
<BlogPost post={EXAMPLE_POST} />
</IntlProvider>
</div>
);
}
function getLocale() {
return window.navigator.languages?.[0] ??
window.navigator.language;
}
As a result, if the effect modifies the UI, the user will see
the initial UI version very quickly before seeing the
updated one, creating a visual glitch.
🏖 https://codesandbox.io/p/sandbox/use-
layout-effect-hqhnld
Example
function Form() {
const id = useId();
return (
<div className="App">
<div>
<label>
Name <input type="text" aria-
describedby={id} />
</label>
</div>
<span id={id}>Make sure to include
full name</span>
</div>
);
}
function createLogger() {
let logs = [];
let listeners = [];
return {
getLogs: () => Object.freeze(logs),
subscribe: (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter((l) =>
l !== listener);
};
},
info: (message) => {
pushLog({ level: "info", message });
console.info(message);
},
error: (message) => {
pushLog({ level: "error", message });
console.error(message);
},
warn: (message) => {
pushLog({ level: "warn", message });
console.warn(message);
},
};
Made with ❤ by Ndeye Fatou Diop
101 React Tips & Tricks 109 / 140
🏖 https://codesandbox.io/p/sandbox/sync-
external-storage-rkq2zq
🏖 https://codesandbox.io/p/sandbox/countries-
app-use-deferred-value-4nh73p
<Map
maxPopulationSize=
{deferredMaxPopulationSize}
// …
/>
formik
React Hook Form, or
or TanStack Form
Format.js
Lingui
react-i18next
If you're like me, you've written the same hooks over and
over again.
By setting editor.stickyScroll.enabled to
true , the current component will always be at the top
of the screen.
const MyComponent = ({
leftElement,
rightElement,
}: {
leftElement: ReactNode,
rightElement: ReactNode,
}) => {
// …
};
// 🟠 Ok
const HeaderPage = ({
children,
...pageProps
}: { children: ReactNode } & PageProps) =>
{
// …
};
// ✅Better
const HeaderPage = ({
children,
...pageProps
}: PropsWithChildren<PageProps>) => {
// …
};
For example, let's say you want a button that will log to
the console when clicked.
// 🟠 Ok
const MyComponent = ({
onClick,
onFocus,
onChange,
}: {
onClick: (e:
// ✅ Better
const MyComponent = ({
onClick,
onFocus,
onChange,
}: {
onClick:
MouseEventHandler<HTMLButtonElement>,
onFocus:
FocusEventHandler<HTMLButtonElement>,
onChange:
ChangeEventHandler<HTMLInputElement>,
}) => {
// …
};
// ✅ Good
const [selectedItemId, setSelectedItemId] =
(useState < string) | (undefined >
undefined);
const logFunctions = {
info: (message: string) =>
console.info(message),
warn: (message: string) =>
console.warn(message),
error: (message: string) =>
console.error(message),
};
The hook returns a ref to use with the div element and
a boolean indicating whether the div is hovered.
interface Size {
width: number;
height: number;
}
interface Widget {
title: string;
type ListItem =
| { type: "follower", follower: Follower
}
| { type: "post", post: Post };
function ListBad({
items,
title,
vertical = true,
ascending = true,
}: {
title: string,
items: ListItem[],
vertical?: boolean,
ascending?: boolean,
}) {
const sortedItems = [...items].sort((a,
b) => {
const sign = ascending ? 1 : -1;
return sign * compareItems(a, b);
});
return (
<div>
<h3 className="title">{title}</h3>
<div className={`list ${vertical ?
"vertical" : ""}`}>
{sortedItems.map((item) => (
<div key={getItemKey(item)}>
{renderItem(item)}</div>
))}
</div>
</div>
);
}
return item.post.id;
}
}
const position = { x: 1, y: 2, z: 3 };
teleportPlayer(position, ["LeynTir",
"Forin", "Karin"], "Forin");
teleportPlayer(position, ["LeynTir",
"Karin"], "anythingCanGoHere"); // This ❌
will work, but it is wrong since
"anythingCanGoHere" shouldn't be a valid
location
locations: L[],
defaultLocation: NoInfer<L>
): NoInfer<L> {
// Teleport the player and return the
location
}
teleportPlayer(position, ["LeynTir",
"Karin"], "anythingCanGoHere"); // ❌
Error: Argument of type
'"anythingCanGoHere"' is not assignable to
parameter of type '"LeynTir" | "Karin"
Especially as a beginner 🐣.
So start with online IDEs like Code Sandbox or
Stackblitz.
You can learn a lot from other developers and share your
knowledge.
CONCLUSION
I hope this book has helped you learn some new React
tips and tricks . 🚀
I look forward to seeing what you build with React - feel
free to let me know how it's going on X/Twitter. You can
reach me at @_ndeyefatoudiop.
A NOTE ON SHARING