Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix inline code #9

Merged
merged 1 commit into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions src/react-render-perf/lesson-01/content.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Memoization can be used to avoid unnecessary renders. This is most useful when
the component itself is expensive to render (e.g. the `MathJax` component in
the component itself is expensive to render (e.g. the <code>MathJax</code> component in
webapp) or it renders a lot of descedent components.

Memoization works by saving the rendered output of the component based on the
Expand All @@ -11,11 +11,11 @@ same implementation are considered differen objects.
In order for memoization to have the desired benefit, we don't want the
component to rerender if there are only superficial changes to props.

`React.memo(Component, arePropsEqual?)` by default does a shallow comparison of
<code>React.memo(Component, arePropsEqual?)</code> by default does a shallow comparison of
props and as such isn't able to determine when a prop that's an object or function
is the same or not. We can pass a custom `arePropsEqual` function to override
is the same or not. We can pass a custom <code>arePropsEqual</code> function to override
that behavior. To keep things simple we use a third-party library called
`react-fast-compare` which provides a function that does a deep comparison of
<code>react-fast-compare</code> which provides a function that does a deep comparison of
objects.

```ts
Expand All @@ -34,7 +34,7 @@ export default React.memo(ChildComponent, arePropsEqual);
```

There is a bit of a gotcha here when it comes to props that are functions.
`react-fast-compare` cannot check if two functions are the same. Imagine the
<code>react-fast-compare</code> cannot check if two functions are the same. Imagine the
following scenario:

```ts
Expand All @@ -57,10 +57,10 @@ const ParentComponent = (props: Props) => {
}
```

Each time `ParentComponent` renders, a new copy of `handleClick` will be created
even if the `result` from `useQuery` isn't ready yet. We only want this function
to treated as a new function when `result` changes. React provides a hook called
`useCallback` which does exactly that by memoizing the function.
Each time <code>ParentComponent</code> renders, a new copy of <code>handleClick</code> will be created
even if the <code>result</code> from <code>useQuery</code> isn't ready yet. We only want this function
to treated as a new function when <code>result</code> changes. React provides a hook called
<code>useCallback</code> which does exactly that by memoizing the function.

```ts
import ChildComponent from "./my-component";
Expand All @@ -82,10 +82,10 @@ const ParentComponent = (props: Props) => {
}
```

If the `ParentComponent` is a class-based component, there is no need to memoize
If the <code>ParentComponent</code> is a class-based component, there is no need to memoize
function props that are pre-bound methods. This is because the method never changes
for the component instance. If the prop is an inline function though, e.g.
`onClick={() => { ... }}` it should be converted to a pre-bound method, see the
<code>onClick=\{() => \{ ... \}\}</code> it should be converted to a pre-bound method, see the
example below.

```ts
Expand Down Expand Up @@ -131,5 +131,5 @@ what to memoize.
## Exercise

1. Use the profiler in React dev tools to measure the render performance of the code in the "exercise" folder.
2. Update the code in the "exercise" folder memoize the `Child` component to avoid rerender this component.
2. Update the code in the "exercise" folder memoize the <code>Child</code> component to avoid rerender this component.
3. Use the profiler in React dev tools to measure the render performance again
20 changes: 10 additions & 10 deletions src/react-render-perf/lesson-02/content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ In order to avoid re-rendering all of the descendents we'd like only those
components using the context to re-render. Ideally, they should only re-render
if the data that they're making use of changes.

In the following example, everytime we update the `value` in the context, we
In the following example, everytime we update the <code>value</code> in the context, we
re-render both child components of the context even though only one of them
needs to be updated.

Expand Down Expand Up @@ -47,13 +47,13 @@ const Parent = () => {
```

To avoid this problem we can replace the plain old JavaScript object being
used for the context's `value` with a event emitter instance. The instance is
only created once and is never replaced so the `value` never changes which
used for the context's <code>value</code> with a event emitter instance. The instance is
only created once and is never replaced so the <code>value</code> never changes which
means that the context will never trigger a re-render.

The child components will register event listeners for changes to only the
data they care about. The parent component will emit the appropriate event when
increment the values for `foo` and `bar`.
increment the values for <code>foo</code> and <code>bar</code>.

```tsx
import {createContext, useContext, useState, useMemo} from "react";
Expand Down Expand Up @@ -102,10 +102,10 @@ const Parent = () => {
};
```

This is necessary but not sufficient to prevent both `Foo` and `Bar` from
re-rendering when either `foo` or `bar` is incremented. That's because
`Parent` is re-rendering when its state changes. To avoid this issue we also
need to memoize `Foo` and `Bar` themselves. Thankfully they don't take any
This is necessary but not sufficient to prevent both <code>Foo</code> and <code>Bar</code> from
re-rendering when either <code>foo</code> or <code>bar</code> is incremented. That's because
<code>Parent</code> is re-rendering when its state changes. To avoid this issue we also
need to memoize <code>Foo</code> and <code>Bar</code> themselves. Thankfully they don't take any
props so this is trivial to do.

```tsx
Expand Down Expand Up @@ -133,7 +133,7 @@ const Bar = memo(() => {

1. Use the profiler in React dev tools to measure the render performance of the
code in the "exercise" folder.
2. Update the code in the "exercise" folder to use an `EventEmitter` to prevent
the `value` in the context provider from changing.
2. Update the code in the "exercise" folder to use an <code>EventEmitter</code> to prevent
the <code>value</code> in the context provider from changing.
3. Memoize only the necessary components to prevent unecessary re-renders.
4. Use the profiler in React dev tools to measure the render performance again.
6 changes: 3 additions & 3 deletions src/react-render-perf/lesson-03/content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ benefits over React Context:
## Example

Using our example from [Lesson 2](/react-render-perf/lesson-02) we can replace the context
by creating an `EventEmitter` singleton and using it directly in our components.
by creating an <code>EventEmitter</code> singleton and using it directly in our components.

```tsx
import {createContext, useContext, useState, useMemo} from "react";
Expand Down Expand Up @@ -68,10 +68,10 @@ const Parent = () => {

While singletons are sometimes frowned upon because they can make testing more
difficult in some languages, that isn't the case in JavaScript. It's easy to mock
the singleton using `jest` if follow these guidelines:
the singleton using <code>jest</code> if follow these guidelines:

- Export the singleton from its own file.
- If you have a custom class instead of using `EventEmitter` be sure to export
- If you have a custom class instead of using <code>EventEmitter</code> be sure to export
that as well so that you can use it when mocking the singleton.

## Exercise
Expand Down
14 changes: 7 additions & 7 deletions src/react-render-perf/lesson-04/content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ prevent them from re-rendering in response to props changes.

## Example

Consider `LargeComponent` below. Clicking on either of the buttons will cause
Consider <code>LargeComponent</code> below. Clicking on either of the buttons will cause
the whole component to re-render.

```tsx
Expand Down Expand Up @@ -55,7 +55,7 @@ const LargeComponent = () => {
}
```

Extracting components `Foo` and `Bar` allows those components to update and
Extracting components <code>Foo</code> and <code>Bar</code> allows those components to update and
re-render indepedently of each other.

```tsx
Expand Down Expand Up @@ -104,7 +104,7 @@ const ParentComponent = () => {

## Notes

- If there are still other things left in the `ParentComponent` that could
- If there are still other things left in the <code>ParentComponent</code> that could
trigger a re-render, you may want to memoize some or all of the children components.
- Splitting up components has the added benefit of making the components easier
to test. You can even mock the child components when testing the parent component.
Expand All @@ -113,7 +113,7 @@ const ParentComponent = () => {

1. Use the profiler in React dev tools to measure the render performance of the code
in the "exercise" folder.
2. Split `LargeComponent` in the exercise/ folder into a `Parent` component and
2. Split <code>LargeComponent</code> in the exercise/ folder into a <code>Parent</code> component and
multiple child components.
3. Memoize components as necessary to address remaining render performance issues.
4. Use the profiler in React dev tools to measure the render performance again.
Expand All @@ -122,8 +122,8 @@ const ParentComponent = () => {

The following pattern can be quite useful when writing jest tests for large components
that render a number of subcomponents. The subcomponents can be mocked with module
mocks to return simple strings that are easy to find using `@testing-library/react`'s
`screen.findByText()`.
mocks to return simple strings that are easy to find using <code>@testing-library/react</code>'s
<code>screen.findByText()</code>.

```ts
import {render, screen} from "@testing-library/react";
Expand Down Expand Up @@ -169,4 +169,4 @@ describe("Parent", () => {
});
```

NOTE: The extra `{}` in the call to `toHaveBeenCalledWith` is necessary.
NOTE: The extra <code>{}</code> in the call to <code>toHaveBeenCalledWith</code> is necessary.
Loading