Adding more articles pages.

reactors
Thomas Hintz 2 years ago
parent 963b4c2703
commit 3f04166894

@ -3,8 +3,10 @@ const nextConfig = {
reactStrictMode: true,
experimental: {
appDir: true,
mdxRs: true,
},
output: 'standalone'
}
module.exports = nextConfig
const withMDX = require('@next/mdx')()
module.exports = withMDX(nextConfig)

4135
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -14,6 +14,7 @@
"@headlessui/react": "^1.7.7",
"@heroicons/react": "^2.0.13",
"@next/font": "13.1.4",
"@next/mdx": "^13.1.6",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.7",

@ -0,0 +1,17 @@
"use client"
import { Article } from '@/components/Components';
import PageContents from './page.mdx';
export default function Page() {
return (
<Article
title="Learn JavaScript Fundamentals: Arrays"
datetime="2021-08-31"
datetitle="August 31st, 2021"
author="Mackenzie Hanna"
>
<PageContents />
</Article>
);
}

@ -0,0 +1,56 @@
Array Basics and Array Methods Used in React
Its time to take a step back and take a look at arrays. Arrays are a powerful tool that can make for more efficient code. React uses arrays in a variety of different ways, but were going to begin with the basics of arrays in Javascript.
What are arrays?
Arrays are objects that contain items stored in a single variable. Arrays consist of stored items, or elements, and each element in an array has a location demarcated by a numerical index which allows for access to each element. The ability to access individual elements makes for handy approaches to make your coding more efficient.
Generally arrays are declared with an array name and sometimes the array length (the number of stored elements). Javascript uses the square bracket notation [ ] to create arrays. It is best practice to keep only one data type in your array such as strings, numbers, or objects only. Below we can create our first empty array:
````
let animals = []
````
“animals” is our variable, and it now contains an empty array. Using the length property will let us verify this:
```{javascript}
console.log(animals.length); //expected output: 0
````
Now if we store some elements in our array and use the length property again, we will see a different output:
```{javascript}
animals = [Nebula, Loki, Aviendha, Munchkin, Galasper];
console.log(animals.length); //expected output: 4
```
Our array is made up of strings and has a length of 4. If we want to access an element, we can do so by using the numerical index for the element we want (It is important to note that the first elements index is 0, and not 1): 
```{javascript]
console.log(animals[0]);  //expected output: Nebula
console.log(animals[4]); //expected output: Galasper
```
Now that our array is created, we can start playing around with the methods used on arrays.
## Adding & Removing Array Elements
### push() Method
The push() method allows us to append our arrays by “pushing” one or more new items to the end of an array. In our case, well be adding a fifth element Squeakers to then end of our array:
```{javascript}
animals.push(Squeakers);
console.log(animals); //expected output: [Nebula, Loki, Aviendha, Munchkin, Galasper, Squeakers]
```
## pop() Method
Conversely, we can remove the last element of our array using the pop() method as shown below. In this case we do not need to pass a value to pop(); it will automatically remove the last element in the array:
```{javascript}
animals.pop();
console.log(animals); //expected output: [Nebula, Loki, Aviendha, Munchkin, Galasper]
```

@ -0,0 +1,17 @@
"use client"
import { Article } from '@/components/Components';
import PageContents from './page.mdx';
export default function Page() {
return (
<Article
title="Next.js vs Create-React-App"
datetime="2021-08-12"
datetitle="August 12th, 2021"
author="Mackenzie Hanna"
>
<PageContents />
</Article>
);
}

@ -0,0 +1,44 @@
## Which should you use for your React project and why?
React is a declarative model that aids developers in creating interactive UIs. Each component of React defines a part of an application by JSX Syntax. With an increasing number of features available to configure in a project pipeline, and their complexity of configuration, maintenance of React projects can be difficult and time consuming. Boilerplates such as Create-React-App (CRA), Next.js, and many others were made to solve these problems and cater to an enhanced developer experience. This article will dive into Create-React-App, Next.js and when and why you should use each.
## What is Create-React-App
Create-React-App is a standardized Client-Side Rendering tool used for bootstrapping front-end single-page applications (SPAs) and can be paired with your desired back end, such as Node. By having your application bound to one HTML page that loads the React Apps, errors wont halt development, dependencies wont slow you down, and your build folder can be statically deployed anywhere!
CRA keeps dependencies, such as Webpack and Babel, inside of react-scripts, and minimizes the tedium of working with transpilers and bundlers. Want to update those dependencies? Just update with the new release of react-scripts and youre done without touching your webpack configuration.
With CRA, youll get your time back by eliminating the need for setting up your development environment for your project. Just run a single command, and all the necessary tools to start your project are there. You can begin building your app immediately!
## Advantages of using Create React App:
Create React App is unopinionated, meaning you have the freedom to use any libraries you prefer. CRA also supports Client-Side Rendering to make for simple deployment and application hosting on other sites, such as Amazon S3.
If youre creating a gated application, the perks of server-side rendering are lost. Having an application with only authenticated users benefits from client-rendering, which are cheaper and easier to host. The same principle applies when building web applications with recurring users. Though server side rendering has many perks, CRA allows for caching to speed up load times with less effort than Server-Side-Rendering (SSR).
## Disadvantages of using Create React App
Any desired webpack customization will have to involve a third-party tool, or “ejecting” from the configuration, which will cost you the benefits of CRA. And there are limits to what is supported. If you need something in your project that CRA doesnt support by default, then you could find yourself in the weeds. The same benefit of easily setting up your development environment becomes a setback by complicating customization. Lastly, Create-React-App struggles with SEO since we are rendering on the client-side, and server-side rendering with CRA will involve a lot of time and effort with setting up bundling, code splitting, page load performance, and more. Avoid using CRA for e-commerce or marketing projects.
## Best Scenarios for using Create React App
If youre creating an SPA, your app uses server APIs, youre looking to start or experiment with React, OR youre trying a new React project and want freedom of choosing libraries, you might want to use CRA. However, we believe there is a better option out there: Next.js.
## What is Next.js?
Next.js is an open-source framework that has been gaining traction with programmers and companies alike (just look at some of the companies that use Next.js for their sites!). Next.js is based on Node.js and Babel built by Vercel. Like Create-React-App, it is used to build SPAs with dynamic routes but differs in that it supports Server-Side-Rendering (SSR) along with a host of other features to create a production-ready app. Some of those other features include: Faster development compilation, automatic build size optimization, static site generation (SSG), and pre-rendering.
Next.js provides smooth integration with back and front end development for complicated web applications. Next.js can be utilized as a web server or integrated into larger node applications that use React as the rendering engine. Like CRA, dependency problems such as outdated webpack wont get in the way of getting your app started or updated!
Using Next.js To Quickly Bootstrap a High Performance React Application
Using SSR and SSG with performance optimizations (like image and font optimization) makes Next.js apps speedy. Deploying full-stack React applications has never been easier! And unlike Create-React-App, its a simple thing to customize your webpacks by adding webpack loaders. Next.js also supplies a quick and intuitive path to build APIs within your application. Its API routes are ideal for working with third-party APIs. All of these advantages make Next.js the leading choice for developers, particularly when building landing pages and other marketing materials. Server-side rendering lends itself to making Next.js the top choice for optimized SEO as well as much faster loading times when building websites. The development experience is also enhanced with built-in features such as: Code Splitting, Prefetching, and Hot Reloading.
The main disadvantage of Next.js is that its opinionated. Contrasted with the freedom of CRA, Next.js is limited to its file-based router, however, dynamic routes are possible when using a Node.js server. Even though this file-based route system is considered a disadvantage to some, it would take weeks to get the same type of route system with CRA.
## Optimal Use Cases for Using Next.js
If your app has a server AND client side, youre looking to building a dynamic website, have dynamic content OR youre looking to optimize SEO on your site, Next.js is highly recommended. The simplicity of Next.js, along with the wealth of documentation available, will allow you to get started on your app idea, even if you arent well-versed in JavaScript.
## Conclusions
Both Next.js and CRA are awesome frameworks for developing React apps. Although choosing one of the other will depend on your specific use case for your project, we recommend Next.js. Containing the best of CRAs functions, Next.js truly has everything you need to turn your idea into an application without getting bogged down under the hood with details. If you want to skip the tutorials and configuration, Next.js is your best choice to getting your React project up and running.

@ -0,0 +1,17 @@
"use client"
import { Article } from '@/components/Components';
import PageContents from './page.mdx';
export default function Page() {
return (
<Article
title="An Overview of React Hooks"
datetime="2021-08-20"
datetitle="August 20th, 2021"
author="Mackenzie Hanna"
>
<PageContents />
</Article>
);
}

@ -0,0 +1,51 @@
import Image from 'next/image'
import screenShot1 from '@/images/screen-shot1.png'
import screenShot2 from '@/images/screen-shot2.png'
import screenShot3 from '@/images/screen-shot3.png'
## What are Hooks?
As someone newly entering the world of React, Hooks were one of the first things brought to my attention. After getting a taste of class-based components, React Hooks came up on my plate as a topic I should review. Although the official React site says that Hooks are “completely opt-in,” and can be used in tandem with your existing classes, my reading has shown that Hooks are highly recommended in the React Community.
Prior to the introduction of React Hooks, state was not able to be used by functional (stateless) components, so class (stateful) components were necessary to define state in the component. Because of this, complex components with stateful logic were not easy to break down or reuse. With the power of Hooks, JavaScript functions give you the capability to “hook into” stateful features of a React Component, meaning you can declare state variables without classes and reuse stateful features among components. And because Hooks are JavaScript functions, you can use Reacts built-in Hooks to create “Custom Hooks” that can be utilized throughout your application. Lets take a high-level look at the built-in Hooks that React provides.
## Two main types of React Hooks
### State Hook Example:
State Hooks are easily imported and allow you to add React state to function components. The most common State Hook is useState, which replaces the need to create a class component using this.state. The below example demonstrates usetate in a functional component “Animorphs.”
<Image src={screenShot1} alt="source code" />
The useState Hook gives us an initial state value, in this case the animal name “Munchkin”, and returns an array (using array destructuring syntax) with 2 items: “animal” and “setAnimal.” “animal” is the current value, and “setAnimal” is a function that, when called by the onClick event listener, updates the name of our animal! For more on State Hooks, visit [https://reactjs.org/docs/hooks-state.html](https://reactjs.org/docs/hooks-state.html)!
## Effect Hook Example:
The next type of React Hook is an Effect Hook, which permits the use of lifecycle methods and performing side effects in functional components. Side effects are when a component's state or variable changes based on a procedure outside of its scope. The useEffect Hook effectively replaces componentDidMount, componentDidUpdate, and componentWillUnmount all in one. You can begin with useEffect by importing it just like we did useState.
<Image src={screenShot2} alt="source code" />
Continuing with our example on useState, useEffect is put inside our function component in order to access our props, in this case the “animal” state variable. Our effect, passing a function to the useEffect Hook, sets the document title with the browser API after React updates the DOM. Whenever the component state changes, or new props are received, the component will re-render and the useEffect hook will run. useState and useEffect are considered the two most important hooks, but there are several others.To see a complete list of APIs of built-in React Hooks, visit [https://reactjs.org/docs/hooks-reference.html](https://reactjs.org/docs/hooks-reference.html).
## React Hooks Rules
### Call Hooks at the Top Level Only
Do not call your Hook inside loops, conditions (BUT conditions can be put inside your Hook), or nested functions. By following this rule, React is able to accurately preserve Hook states between useState and useEffect calls because Hooks will be called in the same order every component rend.
## Call Hooks from React Components Only
Do not call your Hooks from JavaScript functions, only React function components or your own custom Hooks. The Hook will not be accessible in a regular JavaScript function OR when imported without importing React as well.
## Call Hooks from Custom Hooks
JavaScript functions that have a name beginning with “use” and may call other Hooks are considered Custom Hooks. Below is an example of creating a Custom Hook:
<Image src={screenShot3} alt="source code" />
In this example, our custom Hook is “useAnimal” using the custom argument “animal.” “useAnimal” is now called in the function “Animorphs” component and can be shared among other components! Custom Hooks can share stateful logic between components in your application without bulking up your component tree and can be used multiple times in the same component. React also includes a default plugin to ensure these above rules are followed at [https://reactjs.org/docs/hooks-rules.html#eslint-plugin](https://reactjs.org/docs/hooks-rules.html#eslint-plugin).
## Conclusion
With the React community embracing Hooks, the number of React concepts you need to juggle in your application is minimized. Hooks allows for the utilization and reuse of function components rather than shifting between functions, classes, higher-order components, and render props. Because of this, React plans to cover all use cases of class components, so its time to get learning Hooks!

@ -0,0 +1,17 @@
"use client"
import { Article } from '@/components/Components';
import PageContents from './page.mdx';
export default function Page() {
return (
<Article
title="When should you use React.memo and useMemo?"
datetime="2020-07-17"
datetitle="July 17th, 2020"
author="Thomas Hintz"
>
<PageContents />
</Article>
);
}

@ -0,0 +1,282 @@
To improve performance of your functional components you can use
[`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo) and
[`useMemo`](https://reactjs.org/docs/hooks-reference.html#usememo).
`React.memo` is a higher-order component (HOC) that wraps your
functional component. It then memoizes its rendered output. `useMemo` is
a hook that gets run during the render stage and also memoizes its
output based on an array of dependency inputs. Both of these methods
require you to program in a "pure" style. This means given the same prop
values you always render the same output. `useState` and `useContext`
hooks will also trigger a re-render for components that use
`React.memo`.
If you're working with function based components you should read on but
if you are working with class based components you can learn how to
achieve the same thing with `React.PureComponent` in my article "[When
should you use
React.PureComponent?](./when-should-you-use-react-purecomponent)".
React.memo
------------
``` {.javascript}
const Component = React.memo(MyComponent, areEqual);
```
`React.memo` takes one required argument, your React component, and one
optional argument, a comparison function.
### Eligibility
``` {.javascript}
// Example 1
// Example of a "pure" component
// Returns an H1 denoting whether the pancake was over-cooked
const CookedPancake = ({ batter, bakingTime, maxTime }) => {
if (bakingTime > maxTime) {
return (<h1>{batter} Over-cooked!</h1>);
}
return (<h1>{batter} Cooked Just Perfect!</h1>);
};
```
In the first example we just define a pure component and you can see
that if the props are the same the rendered output will be the same and
the component doesn't reference outside state or use random numbers.
This is the first step in determining if a component is eligible for
`React.memo`.
The next step is determining if the same props are passed in to the
component multiple times or not. Like let's say we are using the
`CookedPancake` component in an app that runs a simulation of baking
times. The app starts simulating baking times from 0 to 10 incrementing
the baking time by 1 for each iteration. In this case `bakingTime` is
not a good candidate for `React.memo` because the `bakingTime` prop is
different every time React goes to render the component so memoization
will provide no benefit.
On the other hand let's say we have multiple different types of pancake
batters in a list and the user is able to re-arrange the order in which
they cook the pancakes. The prop values will be reused every time React
re-renders the list of `CookedPancake` components. And since React may
re-render each `CookedPancake` whenever the order of the list changes
this means we have the right conditions for `React.memo`.
### Usage
``` {.javascript}
// Example 2
// Memoized component
const CookedPancake = React.memo(({ batter, bakingTime, maxTime }) => {
if (bakingTime > maxTime) {
return (<h1>{batter} Over-cooked!</h1>);
}
return (<h1>{batter} Cooked Just Perfect!</h1>);
});
// Render CookedPancake with the same prop values.
const MyPancakes = () => {
return (
<>
<CookedPancake batter='Swedish'
bakingTime=1
maxTime=1.5
/>
<CookedPancake batter='Swedish'
bakingTime=1
maxTime=1.5
/>
</>
);
};
```
In Example 2 we add `React.memo` to the component definition and add the
`MyPancakes` component that renders two Swedish `CookedPancake`. When
React renders the first `CookedPancake` it will run the component's
render code like normal but when it goes to render the second
`CookedPancake` it will find a stored result matching the same prop
values and instead of running the `CookedPancake` render code it will
just use the result of its stored run (from the first `CookedPancake`
render). It should also be noted that if `CookedPancake` had any child
components their render code would also not be run since their output is
a part of the memoized result. This means you can stop React from
rendering an entire portion of your component tree with `React.memo`.
### Pitfalls
``` {.javascript}
// Example 3
// WRONG, this will not behave as expected
// A button that takes an onClick handler and some text.
const Button = React.memo(({ onClick, text }) => {
return (<button onClick={onClick} text={text});
};
// Use the Button component and log to console when clicked.
const LogButton = () => {
return (
<Button onClick={() => console.log('Log button clicked!')}
text='Log'
/>
);
};
const App = () => {
return (
<>
<LogButton/>
<LogButton/>
</>
);
};
```
It's important to remember that `React.memo` use shallow comparison of
props so passing anonymous functions or Javascript literals will
probably not do what you want, as we can see in Example 3. In this
example we create a simple button that allows an `onClick` handler to be
set and some text for the button. Then we create a `LogButton` that just
logs to the console when it is clicked (and this is where the bug is
too). The `App` component just includes two `LogButton` components. If
this behaved the way we might expect then we would expect React to not
re-render `LogButton` when it gets to the second `LogButton` in `App`
because it appears as if the props to `Button` are the same. But, in
fact, they are not the same at all. The `onClick` handler is an
anonymous function that Javascript creates every time it renders that
code. So even though what the function does is constant a new Javascript
object is allocated every time. This means that the memoization function
always thinks the props have changed and will always re-render the
component. Not what we want.
``` {.javascript}
// Example 4
// Re-write LogButton to work with Button's React.memo
const logButtonClicked = () => console.log('Log button clicked!');
const LogButton = () => {
return (
<Button onClick={logButtonClicked}
text='Log'
/>
);
};
```
In Example 4 we can see that moving the definition of the logging
function outside the render path fixes the issue because now the same
function object is always passed to `Button`.
``` {.javascript}
// Example 5
// WRONG, does not work as expected
// We change Button to take text as an object
const Button = React.memo(({ onClick, attributes }) => {
return (<button onClick={onClick} text={attributes.text});
};
const LogButton = () => {
return (
<Button onClick={logButtonClicked}
attributes={{ text: 'Log' }}
/>
);
};
```
Let's say we wanted our button to take an object of attributes that we
could use instead of adding a new prop for every attribute of our
button. This might seem straightforward at first, as we can see in
Example 5 with `{ text: 'Log' }`. But this suffers the same flaw as
Example 3 with the anonymous function. Every time React renders
`LogButton` it will create a new object for `attributes` breaking the
memoization. In this case the fix is the same as for the anonymous
function: don't create object literals in the render path.
### `areEqual`
What if you want to use `React.memo` but the provided shallow comparison
is not enough for your use case? Maybe there is an inexpensive way you
can do a deeper comparison? Well React thought of that too and allows
you to specify a second argument to `React.memo`: `areEqual`.
``` {.javascript}
// areEqual signature
function areEqual(prevProps, nextProps) {}
// Usage with React.memo
React.memo((props) => ..., areEqual);
```
`areEqual` is a function you provide to React that receives `prevProps`
and `nextProps`. You return `true` if passing both `prevProps` and
`nextProps` to your component would yield the same result. Note that
this is the opposite of how `shouldComponentUpdate` works where
returning `true` would cause a re-render. Inside `areEqual` is where you
would do a deep(er) comparison.
### Children
Also make sure that all child components of your memoized component
follow the same rules otherwise they won't re-render when you expect
them to.
`useMemo`
---------
``` {.javascript}
const memoizedValue =
useMemo(() => expensiveComputation(x, y), [x, y]);
```
`useMemo` is just a memoization function implemented as a hook that
React provides. It takes two arguments. The first is a function that
performs an expensive computation and the second are the variable
dependencies of that function.
``` {.javascript}
// Example 6
// A pancake component visually representing the pancake's height.
const YummyPancake = ({ batterAmount, batterViscosity }) => {
const thickness = useMemo(
() => calculateThickness(batterAmount, batterViscosity),
[batterAmount, batterViscosity]);
return (
<div className='pancake' style={{ height: thickness }} />
);
};
```
Here we define a `YummyPancake` component that renders a div with its
height determined by the calculated thickness of the pancake. Since
calculating the thickness of a pancake is a very expensive operation and
we might be making many pancakes with the same batter amount and batter
viscosity (very precise chefs) we take advantage of `useMemo`.
In the example `calculateThickness` is called only if `batterAmount` and
`batterViscosity`, the dependent variables, do not have the same values
of any other time that `calculateThickness` was called. This means that
all dependencies of your expensive function should be in the dependency
array. If they are not then React may not call your function to
calculate a new value when you are expecting it to. You'll also notice
that `calculateThickness` is inside an anonymous function. This delays
evaluation so that `useMemo` can decide if and when to execute
`calculateThickness`.
In many ways `useMemo` follows the same rules and guidelines as
`React.memo`. `useMemo` only does a shallow comparison on its
dependencies and expects your expensive function to be pure. So be
careful not to use object literals or anonymous functions in your
dependencies.
In summary, you should use `React.memo` and `useMemo` when rendering is
a bottleneck and you are working with pure functions, props, and
arguments. And if you want to learn more about high performance React
programming subscribe to the email list or the [atom feed](./feed.atom).

@ -0,0 +1,17 @@
"use client"
import { Article } from '@/components/Components';
import PageContents from './page.mdx';
export default function Page() {
return (
<Article
title="When should you use React.PureComponent?"
datetime="2020-07-19"
datetitle="July 19th, 2020"
author="Thomas Hintz"
>
<PageContents />
</Article>
);
}

@ -0,0 +1,245 @@
To improve performance of your class based components you can use
[`React.PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent).
`React.PureComponent` is like `React.Component` except it implements
`componentShouldUpdate` for you. The implementation it provides memoizes
the component based on its props and state using a shallow comparison.
To be able to utilize `React.PureComponent` it is required that you
program in a "pure" style. This means given the same prop and state
values you always render the same output.
If you're working with class based components you should read on but if
you are working with functional components you can learn how to achieve
the same thing with `React.memo` and `useMemo` in my article "[When
should you use React.memo and
useMemo?](./when-should-you-use-react-memo-and-usememo)".
`React.PureComponent`
---------------------
``` {.javascript}
class Pancake extends React.PureComponent {
...
}
```
`React.PureComponent` just replaces the usual `extends React.Component`
with `extends React.PureComponent`.
### Eligibility
Like for `React.memo` and `useMemo` we must first make sure that our
component is eligible for `React.PureComponent`.
``` {.javascript}
// Example 1
// Example of a "pure" component
// Returns an H1 denoting whether the pancake was over-cooked
class CookedPancake extends React.Component {
render() {
const { batter, bakingTime, maxTime } = this.props;
if (bakingTime > maxTime) {
return (<h1>{batter} Over-cooked!</h1>);
}
return (<h1>{batter} Cooked Just Perfect!</h1>);
}
}
```
In the first example we just define a pure component and you can see
that if the props are the same the rendered output will be the same and
the component doesn't reference outside state or use random numbers.
This is the first step in determining if a component is eligible for
`React.PureComponent`.
The next step is determining if the same props are passed in to the
component multiple times or not. Like let's say we are using the
`CookedPancake` component in an app that runs a simulation of baking
times. The app starts simulating baking times from 0 to 10 incrementing
the baking time by 1 for each iteration. In this case `bakingTime` is
not a good candidate for `React.memo` because the `bakingTime` prop is
different every time React goes to render the component so memoization
will provide no benefit.
On the other hand let's say we have multiple different types of pancake
batters in a list and the user is able to re-arrange the order in which
they cook the pancakes. The prop values will be reused every time React
re-renders the list of `CookedPancake` components. And since React may
re-render each `CookedPancake` whenever the order of the list changes
this means we have the right conditions for `React.PureComponent`.
### Usage
``` {.javascript}
// Example 2
// Memoized component
// Only the class signature has changed:
class CookedPancake extends React.PureComponent {
render() {
const { batter, bakingTime, maxTime } = this.props;
if (bakingTime > maxTime) {
return (<h1>{batter} Over-cooked!</h1>);
}
return (<h1>{batter} Cooked Just Perfect!</h1>);
}
}
// Render CookedPancake with the same prop values.
class MyPancakes extends React.Component {
render() {
return (
<>
<CookedPancake batter='Swedish'
bakingTime=1
maxTime=1.5
/>
<CookedPancake batter='Swedish'
bakingTime=1
maxTime=1.5
/>
</>
);
}
};
```
In Example 2 we add `React.PureComponent` to the component class
definition and add the `MyPancakes` component that renders two Swedish
`CookedPancake`. When React renders the first `CookedPancake` it will
run the component's render code like normal but when it goes to render
the second `CookedPancake` it will find a stored result matching the
same prop values and instead of running the `CookedPancake` render code
it will just use the result of its stored run (from the first
`CookedPancake` render). It should also be noted that if `CookedPancake`
had any child components their render code would also not be run since
their output is a part of the memoized result. This means you can stop
React from rendering an entire portion of your component tree with
`React.PureComponent`.
### Pitfalls
``` {.javascript}
// Example 3
// WRONG, this will not behave as expected
// A button that takes an onClick handler and some text.
class Button extends React.PureComponent {
render() {
const { onClick, text } = this.props;
return (<button onClick={onClick} text={text});
}
};
// Use the Button component and log to console when clicked.
class LogButton extends React.Component {
render() {
return (
<Button onClick={() => console.log('Log button clicked!')}
text='Log'
/>
);
}
};
class App extends React.Component {
render() {
return (
<>
<LogButton/>
<LogButton/>
</>
);
}
};
```
It's important to remember that `React.PureComponent` use shallow
comparison of props so passing anonymous functions or Javascript
literals will probably not do what you want, as we can see in Example 3.
In this example we create a simple button that allows an `onClick`
handler to be set and some text for the button. Then we create a
`LogButton` that just logs to the console when it is clicked (and this
is where the bug is too). The `App` component just includes two
`LogButton` components. If this behaved the way we might expect then we
would expect React to not re-render `LogButton` when it gets to the
second `LogButton` in `App` because it appears as if the props to
`Button` are the same. But, in fact, they are not the same at all. The
`onClick` handler is an anonymous function that Javascript creates every
time it renders that code. So even though what the function does is
constant a new Javascript object is allocated every time. This means
that the memoization function always thinks the props have changed and
will always re-render the component. Not what we want.
``` {.javascript}
// Example 4
// Re-write LogButton to work with Button's PureComponent usage
const logButtonClicked = () => console.log('Log button clicked!');
class LogButton extends React.Component {
render() {
return (
<Button onClick={logButtonClicked}
text='Log'
/>
);
}
};
```
In Example 4 we can see that moving the definition of the logging
function outside the render path fixes the issue because now the same
function object is always passed to `Button`.
``` {.javascript}
// Example 5
// WRONG, does not work as expected
// We change Button to take text as an object
class Button extends React.PureComponent {
render() {
const { onClick, attributes } = this.props;
return (<button onClick={onClick} text={attributes.text});
}
};
class LogButton extends React.Component {
render() {
return (
<Button onClick={logButtonClicked}
attributes={{ text: 'Log' }}
/>
);
}
};
```
Let's say we wanted our button to take an object of attributes that we
could use instead of adding a new prop for every attribute of our
button. This might seem straightforward at first, as we can see in
Example 5 with `{ text: 'Log' }`. But this suffers the same flaw as
Example 3 with the anonymous function. Every time React renders
`LogButton` it will create a new object for `attributes` breaking the
memoization. In this case the fix is the same as for the anonymous
function: don't create object literals in the render path.
So far we've just been looking at props but React also includes the
component's state in the memoization so make sure you follow the same
rules for state as you would for props.
If you have nested state and still want to use `React.PureComponent` you
can do so by utilizing React's `forceUpdate` API but this not
recommended as it can lead to code that is more difficult to understand
and use.
### Children
Also make sure that all child components of your memoized component
follow the same rules otherwise they won't re-render when you expect
them to.
In summary, you should use `React.PureComponent` when rendering is a
bottleneck and you are working with pure components, props, state, and
arguments. And if you want to learn more about high performance React
programming subscribe to the email list or the [atom feed](./feed.atom).

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

@ -0,0 +1,5 @@
import { H2, P } from '@/components/Components';
export function useMDXComponents(components) {
return { h2: H2, p: P, ...components };
}
Loading…
Cancel
Save