From 08b6e4b8761db4993ec9d61322c87a653958c96a Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 24 Jan 2019 18:00:04 +0000 Subject: [PATCH 01/26] Update docs for stable Hooks --- content/docs/hooks-custom.md | 8 ++++---- content/docs/hooks-effect.md | 8 ++++---- content/docs/hooks-faq.md | 25 ++++++++++++++++++++++--- content/docs/hooks-intro.md | 12 ++++++++++-- content/docs/hooks-overview.md | 10 +++++----- content/docs/hooks-reference.md | 15 ++++++++------- content/docs/hooks-rules.md | 4 ++-- content/docs/hooks-state.md | 12 ++++++------ content/docs/nav.yml | 2 +- 9 files changed, 62 insertions(+), 34 deletions(-) diff --git a/content/docs/hooks-custom.md b/content/docs/hooks-custom.md index b48f7f78..4d10032b 100644 --- a/content/docs/hooks-custom.md +++ b/content/docs/hooks-custom.md @@ -6,14 +6,14 @@ next: hooks-reference.html prev: hooks-rules.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. Building your own Hooks lets you extract component logic into reusable functions. When we were learning about [using the Effect Hook](/docs/hooks-effect.html#example-using-hooks-1), we saw this component from a chat application that displays a message indicating whether a friend is online or offline: ```js{4-15} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); @@ -39,7 +39,7 @@ function FriendStatus(props) { Now let's say that our chat application also has a contact list, and we want to render names of online users with a green color. We could copy and paste similar logic above into our `FriendListItem` component but it wouldn't be ideal: ```js{4-15} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function FriendListItem(props) { const [isOnline, setIsOnline] = useState(null); @@ -74,7 +74,7 @@ When we want to share logic between two JavaScript functions, we extract it to a **A custom Hook is a JavaScript function whose name starts with "`use`" and that may call other Hooks.** For example, `useFriendStatus` below is our first custom Hook: ```js{3} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); diff --git a/content/docs/hooks-effect.md b/content/docs/hooks-effect.md index b0104538..dbe26375 100644 --- a/content/docs/hooks-effect.md +++ b/content/docs/hooks-effect.md @@ -6,12 +6,12 @@ next: hooks-rules.html prev: hooks-intro.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. The *Effect Hook* lets you perform side effects in function components: ```js{1,6-10} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); @@ -94,7 +94,7 @@ Now let's see how we can do the same with the `useEffect` Hook. We've already seen this example at the top of this page, but let's take a closer look at it: ```js{1,6-8} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); @@ -199,7 +199,7 @@ Let's see how we could write this component with Hooks. You might be thinking that we'd need a separate effect to perform the cleanup. But code for adding and removing a subscription is so tightly related that `useEffect` is designed to keep it together. If your effect returns a function, React will run it when it is time to clean up: ```js{10-16} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 74d9227e..abd57a0b 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -5,7 +5,7 @@ permalink: docs/hooks-faq.html prev: hooks-reference.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. This page answers some of the frequently asked questions about [Hooks](/docs/hooks-overview.html). @@ -19,7 +19,9 @@ This page answers some of the frequently asked questions about [Hooks](/docs/hoo --> * **[Adoption Strategy](#adoption-strategy)** + * [Which versions of React include Hooks?](#which-versions-of-react-include-hooks) * [Do I need to rewrite all my class components?](#do-i-need-to-rewrite-all-my-class-components) + * [What can I do with Hooks that I couldn't with classes?](#what-can-i-do-with-hooks-that-i-couldnt-with-classes) * [How much of my React knowledge stays relevant?](#how-much-of-my-react-knowledge-stays-relevant) * [Should I use Hooks, classes, or a mix of both?](#should-i-use-hooks-classes-or-a-mix-of-both) * [Do Hooks cover all use cases for classes?](#do-hooks-cover-all-use-cases-for-classes) @@ -51,10 +53,27 @@ This page answers some of the frequently asked questions about [Hooks](/docs/hoo ## Adoption Strategy +### Which versions of React include Hooks? + +Starting with 16.8.0, React includes a stable implementation of React Hooks for: + +* React DOM +* React DOM Server +* React Test Renderer +* React Shallow Renderer + +Note that **to enable Hooks, all React packages need to be 16.8.0 or higher**. Hooks won't work if you forget to update, for example, React DOM. + +React Native will fully support Hooks in its next stable release. + ### Do I need to rewrite all my class components? No. There are [no plans](/docs/hooks-intro.html#gradual-adoption-strategy) to remove classes from React -- we all need to keep shipping products and can't afford rewrites. We recommend trying Hooks in new code. +### What can I do with Hooks that I couldn't with classes? + +Hooks offer a powerful and expressive new way to reuse functionality between components. ["Building Your Own Hooks"](/docs/hooks-custom.html) provides a glimpse of what's possible. [This article](https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889) by a React core team member dives deeper into the new capabilities unlocked by Hooks. + ### How much of my React knowledge stays relevant? Hooks are a more direct way to use the React features you already know -- such as state, lifecycle, context, and refs. They don't fundamentally change how React works, and your knowledge of components, props, and top-down data flow is just as relevant. @@ -71,7 +90,7 @@ You can't use Hooks *inside* of a class component, but you can definitely mix cl Our goal is for Hooks to cover all use cases for classes as soon as possible. There are no Hook equivalents to the uncommon `getSnapshotBeforeUpdate` and `componentDidCatch` lifecycles yet, but we plan to add them soon. -It is a very early time for Hooks, so some integrations like DevTools support or Flow/TypeScript typings may not be ready yet. Some third-party libraries might also not be compatible with Hooks at the moment. +It is an early time for Hooks, and some third-party libraries might not be compatible with Hooks at the moment. ### Do Hooks replace render props and higher-order components? @@ -85,7 +104,7 @@ In the future, new versions of these libraries might also export custom Hooks su ### Do Hooks work with static typing? -Hooks were designed with static typing in mind. Because they're functions, they are easier to type correctly than patterns like higher-order components. We have reached out both to Flow and TypeScript teams in advance, and they plan to include definitions for React Hooks in the future. +Hooks were designed with static typing in mind. Because they're functions, they are easier to type correctly than patterns like higher-order components. The latest Flow and TypeScript React definitions include support for React Hooks. Importantly, custom Hooks give you the power to constrain React API if you'd like to type them more strictly in some way. React gives you the primitives, but you can combine them in different ways than what we provide out of the box. diff --git a/content/docs/hooks-intro.md b/content/docs/hooks-intro.md index b6e59537..aea40197 100644 --- a/content/docs/hooks-intro.md +++ b/content/docs/hooks-intro.md @@ -5,10 +5,10 @@ permalink: docs/hooks-intro.html next: hooks-overview.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. ```js{4,5} -import { useState } from 'react'; +import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" @@ -29,6 +29,10 @@ This new function `useState` is the first "Hook" we'll learn about, but this exa **You can start learning Hooks [on the next page](/docs/hooks-overview.html).** On this page, we'll continue by explaining why we're adding Hooks to React and how they can help you write great applications. +>Note +> +>React 16.8.0 is the first release to support Hooks. When upgrading, don't forget to update all packages, including React DOM. React Native will support Hooks in the next stable release. + ## Video Introduction At React Conf 2018, Sophie Alpert and Dan Abramov introduced Hooks, followed by Ryan Florence demonstrating how to refactor an application to use them. Watch the video here: @@ -99,6 +103,10 @@ Finally, there is no rush to migrate to Hooks. We recommend avoiding any "big re We intend for Hooks to cover all existing use cases for classes, but **we will keep supporting class components for the foreseeable future.** At Facebook, we have tens of thousands of components written as classes, and we have absolutely no plans to rewrite them. Instead, we are starting to use Hooks in the new code side by side with classes. +## Frequently Asked Questions + +We've prepared a [Hooks FAQ page](/docs/hooks-faq.html) that answers the most common questions about Hooks. + ## Next Steps By the end of this page, you should have a rough idea of what problems Hooks are solving, but many details are probably unclear. Don't worry! **Let's now go to [the next page](/docs/hooks-overview.html) where we start learning about Hooks by example.** diff --git a/content/docs/hooks-overview.md b/content/docs/hooks-overview.md index 62ce2ab9..d3f2dbd8 100644 --- a/content/docs/hooks-overview.md +++ b/content/docs/hooks-overview.md @@ -6,7 +6,7 @@ next: hooks-state.html prev: hooks-intro.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. Hooks are [backwards-compatible](/docs/hooks-intro.html#no-breaking-changes). This page provides an overview of Hooks for experienced React users. This is a fast-paced overview. If you get confused, look for a yellow box like this: @@ -21,7 +21,7 @@ Hooks are [backwards-compatible](/docs/hooks-intro.html#no-breaking-changes). Th This example renders a counter. When you click the button, it increments the value: ```js{1,4,5} -import { useState } from 'react'; +import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" @@ -77,7 +77,7 @@ The Effect Hook, `useEffect`, adds the ability to perform side effects from a fu For example, this component sets the document title after React updates the DOM: ```js{1,6-10} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); @@ -104,7 +104,7 @@ When you call `useEffect`, you're telling React to run your "effect" function af Effects may also optionally specify how to "clean up" after them by returning a function. For example, this component uses an effect to subscribe to a friend's online status, and cleans up by unsubscribing from it: ```js{10-16} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); @@ -181,7 +181,7 @@ Earlier on this page, we introduced a `FriendStatus` component that calls the `u First, we'll extract this logic into a custom Hook called `useFriendStatus`: ```js{3} -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index 16c58ccf..c3af4239 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -6,7 +6,7 @@ prev: hooks-custom.html next: hooks-faq.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. This page describes the APIs for the built-in Hooks in React. @@ -367,7 +367,7 @@ useDebugValue(value) `useDebugValue` can be used to display a label for custom hooks in React DevTools. -For example, consider the `useFriendStatus` custom hook described in ["Building Your Own Hooks"](/docs/hooks-custom.html): +For example, consider the `useFriendStatus` custom Hook described in ["Building Your Own Hooks"](/docs/hooks-custom.html): ```js{6-8} function useFriendStatus(friendID) { @@ -375,7 +375,7 @@ function useFriendStatus(friendID) { // ... - // Show a label in DevTools next to this hook + // Show a label in DevTools next to this Hook // e.g. "FriendStatus: Online" useDebugValue(isOnline ? 'Online' : 'Offline'); @@ -385,15 +385,16 @@ function useFriendStatus(friendID) { > Tip > -> We don't recommend adding debug values to every custom hook. It's most valuable for custom hooks that are part of shared libraries. +> We don't recommend adding debug values to every custom Hook. It's most valuable for custom Hooks that are part of shared libraries. #### Defer formatting debug values -In some cases formatting a value for display might be an expensive operation. It's also unnecessary unless a hook is actually inspected. +In some cases formatting a value for display might be an expensive operation. It's also unnecessary unless a Hook is actually inspected. -For this reason `useDebugValue` accepts a formatting function as an optional second parameter. This function is only called if the hooks is inspected. It receives the debug value as a parameter and should return a formatted display value. +For this reason `useDebugValue` accepts a formatting function as an optional second parameter. This function is only called if the Hooks are inspected. It receives the debug value as a parameter and should return a formatted display value. + +For example a custom Hook that returned a `Date` value could avoid calling the `toDateString` function unnecessarily by passing the following formatter: -For example a custom hook that returned a `Date` value could avoid calling the `toDateString` function unnecessarily by passing the following formatter: ```js useDebugValue(date, date => date.toDateString()); ``` diff --git a/content/docs/hooks-rules.md b/content/docs/hooks-rules.md index af935c79..20a11360 100644 --- a/content/docs/hooks-rules.md +++ b/content/docs/hooks-rules.md @@ -6,7 +6,7 @@ next: hooks-custom.html prev: hooks-effect.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. Hooks are JavaScript functions, but you need to follow two rules when using them. We provide a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce these rules automatically: @@ -28,7 +28,7 @@ By following this rule, you ensure that all stateful logic in a component is cle We released an ESLint plugin called [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) that enforces these two rules. You can add this plugin to your project if you'd like to try it: ```bash -npm install eslint-plugin-react-hooks@next +npm install eslint-plugin-react-hooks ``` ```js diff --git a/content/docs/hooks-state.md b/content/docs/hooks-state.md index c910268a..35e31fd6 100644 --- a/content/docs/hooks-state.md +++ b/content/docs/hooks-state.md @@ -6,12 +6,12 @@ next: hooks-effect.html prev: hooks-overview.html --- -*Hooks* are an upcoming feature that lets you use state and other React features without writing a class. They're currently in React v16.8.0-alpha.1. +*Hooks* let you use state and other React features without writing a class. The [previous page](/docs/hooks-intro.html) introduced Hooks with this example: ```js{4-5} -import { useState } from 'react'; +import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" @@ -91,7 +91,7 @@ Hooks **don't** work inside classes. But you can use them instead of writing cla Our new example starts by importing the `useState` Hook from React: ```js{1} -import { useState } from 'react'; +import React, { useState } from 'react'; function Example() { // ... @@ -123,7 +123,7 @@ class Example extends React.Component { In a function component, we have no `this`, so we can't assign or read `this.state`. Instead, we call the `useState` Hook directly inside our component: ```js{4,5} -import { useState } from 'react'; +import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" @@ -139,7 +139,7 @@ function Example() { Now that we know what the `useState` Hook does, our example should make more sense: ```js{4,5} -import { useState } from 'react'; +import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" @@ -196,7 +196,7 @@ Let's now **recap what we learned line by line** and check our understanding. But if GitHub got away with it for years we can cheat. --> ```js{1,4,9} - 1: import { useState } from 'react'; + 1: import React, { useState } from 'react'; 2: 3: function Example() { 4: const [count, setCount] = useState(0); diff --git a/content/docs/nav.yml b/content/docs/nav.yml index 01f5942a..4d4a7571 100644 --- a/content/docs/nav.yml +++ b/content/docs/nav.yml @@ -104,7 +104,7 @@ title: JS Environment Requirements - id: glossary title: Glossary -- title: Hooks (Preview) +- title: Hooks (New) isOrdered: true items: - id: hooks-intro From 4d61b4a19d807c20a69328c711307e59f2a8713e Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 25 Jan 2019 15:22:36 +0000 Subject: [PATCH 02/26] Add Hooks to reference page --- content/docs/reference-react.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/content/docs/reference-react.md b/content/docs/reference-react.md index 68a00c4c..e04a2dfc 100644 --- a/content/docs/reference-react.md +++ b/content/docs/reference-react.md @@ -65,6 +65,26 @@ Suspense lets components "wait" for something before rendering. Today, Suspense - [`React.lazy`](#reactlazy) - [`React.Suspense`](#reactsuspense) +### Hooks + +Hooks are a new feature available in React 16.8 and higher. They let you use state and other React features without writing a class. + +They have a [separate](/docs/hooks-intro.html) documentation section and an API reference page: + +- [Basic Hooks](/docs/hooks-reference.html#basic-hooks) + - [`useState`](/docs/hooks-reference.html#usestate) + - [`useEffect`](/docs/hooks-reference.html#useeffect) + - [`useContext`](/docs/hooks-reference.html#usecontext) +- [Additional Hooks](/docs/hooks-reference.html#additional-hooks) + - [`useReducer`](/docs/hooks-reference.html#usereducer) + - [`useCallback`](/docs/hooks-reference.html#usecallback) + - [`useMemo`](/docs/hooks-reference.html#usememo) + - [`useRef`](/docs/hooks-reference.html#useref) + - [`useImperativeHandle`](/docs/hooks-reference.html#useimperativehandle) + - [`useLayoutEffect`](/docs/hooks-reference.html#uselayouteffect) + - [`useDebugValue`](/docs/hooks-reference.html#usedebugvalue) + + * * * ## Reference From f510e11312d6f909ecc00dee28e618c94c46e7a3 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 25 Jan 2019 18:08:48 +0000 Subject: [PATCH 03/26] Reword intro --- content/docs/hooks-custom.md | 2 +- content/docs/hooks-effect.md | 2 +- content/docs/hooks-faq.md | 2 +- content/docs/hooks-intro.md | 2 +- content/docs/hooks-overview.md | 2 +- content/docs/hooks-reference.md | 2 +- content/docs/hooks-rules.md | 2 +- content/docs/hooks-state.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/content/docs/hooks-custom.md b/content/docs/hooks-custom.md index 4d10032b..dbc0459e 100644 --- a/content/docs/hooks-custom.md +++ b/content/docs/hooks-custom.md @@ -6,7 +6,7 @@ next: hooks-reference.html prev: hooks-rules.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. Building your own Hooks lets you extract component logic into reusable functions. diff --git a/content/docs/hooks-effect.md b/content/docs/hooks-effect.md index dbe26375..b40167ec 100644 --- a/content/docs/hooks-effect.md +++ b/content/docs/hooks-effect.md @@ -6,7 +6,7 @@ next: hooks-rules.html prev: hooks-intro.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. The *Effect Hook* lets you perform side effects in function components: diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index abd57a0b..db403bc0 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -5,7 +5,7 @@ permalink: docs/hooks-faq.html prev: hooks-reference.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. This page answers some of the frequently asked questions about [Hooks](/docs/hooks-overview.html). diff --git a/content/docs/hooks-intro.md b/content/docs/hooks-intro.md index aea40197..a7f64bea 100644 --- a/content/docs/hooks-intro.md +++ b/content/docs/hooks-intro.md @@ -5,7 +5,7 @@ permalink: docs/hooks-intro.html next: hooks-overview.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. ```js{4,5} import React, { useState } from 'react'; diff --git a/content/docs/hooks-overview.md b/content/docs/hooks-overview.md index d3f2dbd8..013f792c 100644 --- a/content/docs/hooks-overview.md +++ b/content/docs/hooks-overview.md @@ -6,7 +6,7 @@ next: hooks-state.html prev: hooks-intro.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. Hooks are [backwards-compatible](/docs/hooks-intro.html#no-breaking-changes). This page provides an overview of Hooks for experienced React users. This is a fast-paced overview. If you get confused, look for a yellow box like this: diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index c3af4239..5dd1c75f 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -6,7 +6,7 @@ prev: hooks-custom.html next: hooks-faq.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. This page describes the APIs for the built-in Hooks in React. diff --git a/content/docs/hooks-rules.md b/content/docs/hooks-rules.md index 20a11360..80a44799 100644 --- a/content/docs/hooks-rules.md +++ b/content/docs/hooks-rules.md @@ -6,7 +6,7 @@ next: hooks-custom.html prev: hooks-effect.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. Hooks are JavaScript functions, but you need to follow two rules when using them. We provide a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce these rules automatically: diff --git a/content/docs/hooks-state.md b/content/docs/hooks-state.md index 35e31fd6..2a234af8 100644 --- a/content/docs/hooks-state.md +++ b/content/docs/hooks-state.md @@ -6,7 +6,7 @@ next: hooks-effect.html prev: hooks-overview.html --- -*Hooks* let you use state and other React features without writing a class. +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. The [previous page](/docs/hooks-intro.html) introduced Hooks with this example: From 9d62821e9eb7b91c03bf67f9ee3af79f5e8454cd Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 25 Jan 2019 18:12:30 +0000 Subject: [PATCH 04/26] Tweak refwording --- content/docs/reference-react.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/content/docs/reference-react.md b/content/docs/reference-react.md index e04a2dfc..3ac8c607 100644 --- a/content/docs/reference-react.md +++ b/content/docs/reference-react.md @@ -67,9 +67,7 @@ Suspense lets components "wait" for something before rendering. Today, Suspense ### Hooks -Hooks are a new feature available in React 16.8 and higher. They let you use state and other React features without writing a class. - -They have a [separate](/docs/hooks-intro.html) documentation section and an API reference page: +*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class. Hooks have a [dedicated docs section](/docs/hooks-intro.html) and a separate API reference: - [Basic Hooks](/docs/hooks-reference.html#basic-hooks) - [`useState`](/docs/hooks-reference.html#usestate) @@ -84,7 +82,6 @@ They have a [separate](/docs/hooks-intro.html) documentation section and an API - [`useLayoutEffect`](/docs/hooks-reference.html#uselayouteffect) - [`useDebugValue`](/docs/hooks-reference.html#usedebugvalue) - * * * ## Reference From eaefc81239ac78b5c5ca1a1829b293d4ac77c7df Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 25 Jan 2019 19:22:27 +0000 Subject: [PATCH 05/26] Hooks blog post draft --- content/blog/2019-01-30-react-v16.8.0.md | 97 ++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 content/blog/2019-01-30-react-v16.8.0.md diff --git a/content/blog/2019-01-30-react-v16.8.0.md b/content/blog/2019-01-30-react-v16.8.0.md new file mode 100644 index 00000000..94359c26 --- /dev/null +++ b/content/blog/2019-01-30-react-v16.8.0.md @@ -0,0 +1,97 @@ +--- +title: "React v16.8: The One With Hooks" +author: [gaearon] +--- + +With React 16.8, [React Hooks](/docs/hooks-intro.html) are available in a stable release! + +## What Are Hooks? + +Hooks let you use state and other React features without writing a class. You can also **build your own Hooks** to share reusable stateful logic between components. + +If you've never heard of Hooks before, you might find these resources interesting: + +* [Introducing Hooks](/docs/hooks-intro.html) explains why we're adding Hooks to React. +* [Hooks at a Glance](/docs/hooks-overview.html) is a fast-paced overview of the built-in Hooks. +* [Building Your Own Hooks](/docs/hooks-custom.html) demonstrates code reuse with custom Hooks. +* [Making Sense of React Hooks](https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889) explores the new possibilities unlocked by Hooks. +* [useHooks.com](https://usehooks.com/) showcases community-maintained Hooks recipes and demos. + +**You don't have to learn Hooks right now.** Hooks have no breaking changes, and we have no plans to remove classes from React. The [Hooks FAQ](/docs/hooks-faq.html) describes the gradual adoption strategy. + +## No Big Rewrites + +We don't recommend rewriting your existing applications to use Hooks overnight. Instead, try using Hooks in some of the new components, and let us know what you think. Code using Hooks will work [side by side](/docs/hooks-intro.html#gradual-adoption-strategy) with your existing code using classes. + +## Can I Use Hooks Today? + +Yes! Starting with 16.8.0, React includes a stable implementation of React Hooks for: + +* React DOM +* React DOM Server +* React Test Renderer +* React Shallow Renderer + +Note that **to enable Hooks, all React packages need to be 16.8.0 or higher**. Hooks won't work if you forget to update, for example, React DOM. + +**React Native will fully support Hooks in its next stable release.** + +## Tooling Support + +React Hooks are now fully supported by React DevTools. They are also supported in the latest Flow and TypeScript definitions for React. We recommend using a new [lint rule](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce best practices with Hooks. It will soon be included into Create React App by default. + +## What's Next + +React Hooks don't cover *all* use cases for classes yet but they're [very close](/docs/hooks-faq.html#do-hooks-cover-all-use-cases-for-classes). Currently, only `getSnapshotBeforeUpdate()` and `componentDidCatch()` methods don't have equivalent Hooks APIs, and these lifecycles are relatively uncommon. If you want, you should be able to use Hooks in most of the new code you're writing. + +Even while Hooks were in alpha, we saw many [interesting examples](https://medium.com/@drcmda/hooks-in-react-spring-a-tutorial-c6c436ad7ee4) of custom Hooks for animations, forms, subscriptions, integrating with other libraries, and so on. Our goal is to empower the React community to write components and Hooks that deliver great user and developer experience. We can't wait to see what you'll create next! + +## Thanks + +We'd like to thank everybody who commented on the [Hooks RFC](https://github.com/reactjs/rfcs/pull/68) for sharing their feedback. We've read all of your comments and made some adjustments to the final API based on them. + +## Installation + +React v16.8.0 is available on the npm registry. + +To install React 16 with Yarn, run: + +```bash +yarn add react@^16.8.0 react-dom@^16.8.0 +``` + +To install React 16 with npm, run: + +```bash +npm install --save react@^16.8.0 react-dom@^16.8.0 +``` + +We also provide UMD builds of React via a CDN: + +```html + + +``` + +Refer to the documentation for [detailed installation instructions](/docs/installation.html). + +## Changelog + +### React + +* Adds [Hooks](https://reactjs.org/docs/hooks-intro.html) — a way to use state and other React features without writing a class. ([@acdlite](https://github.com/acdlite) et al. in [#13968](https://github.com/facebook/react/pull/13968)) + +### React DOM + +* Support synchronous thenables passed to `React.lazy()`. ([@gaearon](https://github.com/gaearon) in [#14626](https://github.com/facebook/react/pull/14626)) + +### React Test Renderer + +* Support Hooks in the shallow renderer. ([@trueadm](https://github.com/trueadm) in [#14567](https://github.com/facebook/react/pull/14567)) +* Fix shallow renderer passing incorrect state to `shouldComponentUpdate` in the presence of `getDerivedStateFromProps`. ([@chenesan](https://github.com/chenesan) in [#14613](https://github.com/facebook/react/pull/14613)) + +### ESLint Plugin: React Hooks + +* Initial [release](https://www.npmjs.com/package/eslint-plugin-react-hooks). ([@calebmer](https://github.com/calebmer) in [#13968](https://github.com/facebook/react/pull/13968)) +* Fix reporting after encountering a loop. ([@calebmer](https://github.com/calebmer) and [@Yurickh](https://github.com/Yurickh) in [#13968](https://github.com/facebook/react/pull/13968)) + From 57138d729df8d21f50210b516b3b55caf62ecbf7 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 25 Jan 2019 19:43:46 +0000 Subject: [PATCH 06/26] Link to roadmap from post --- content/blog/2019-01-30-react-v16.8.0.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/content/blog/2019-01-30-react-v16.8.0.md b/content/blog/2019-01-30-react-v16.8.0.md index 94359c26..b431abbd 100644 --- a/content/blog/2019-01-30-react-v16.8.0.md +++ b/content/blog/2019-01-30-react-v16.8.0.md @@ -42,7 +42,9 @@ React Hooks are now fully supported by React DevTools. They are also supported i ## What's Next -React Hooks don't cover *all* use cases for classes yet but they're [very close](/docs/hooks-faq.html#do-hooks-cover-all-use-cases-for-classes). Currently, only `getSnapshotBeforeUpdate()` and `componentDidCatch()` methods don't have equivalent Hooks APIs, and these lifecycles are relatively uncommon. If you want, you should be able to use Hooks in most of the new code you're writing. +We described our plan for the next months in the recently published [React Roadmap](/blog/2018/11/27/react-16-roadmap.html). + +Note that React Hooks don't cover *all* use cases for classes yet but they're [very close](/docs/hooks-faq.html#do-hooks-cover-all-use-cases-for-classes). Currently, only `getSnapshotBeforeUpdate()` and `componentDidCatch()` methods don't have equivalent Hooks APIs, and these lifecycles are relatively uncommon. If you want, you should be able to use Hooks in most of the new code you're writing. Even while Hooks were in alpha, we saw many [interesting examples](https://medium.com/@drcmda/hooks-in-react-spring-a-tutorial-c6c436ad7ee4) of custom Hooks for animations, forms, subscriptions, integrating with other libraries, and so on. Our goal is to empower the React community to write components and Hooks that deliver great user and developer experience. We can't wait to see what you'll create next! From 5da272a3e2b1c768b0492cd8f9e655220220056b Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 29 Jan 2019 17:49:08 +0000 Subject: [PATCH 07/26] Add more details --- content/blog/2019-01-30-react-v16.8.0.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/content/blog/2019-01-30-react-v16.8.0.md b/content/blog/2019-01-30-react-v16.8.0.md index b431abbd..84412abe 100644 --- a/content/blog/2019-01-30-react-v16.8.0.md +++ b/content/blog/2019-01-30-react-v16.8.0.md @@ -85,15 +85,19 @@ Refer to the documentation for [detailed installation instructions](/docs/instal ### React DOM +* Bail out of rendering on identical values for `useState` and `useReducer` Hooks. ([@acdlite](https://github.com/acdlite) in [#14569](https://github.com/facebook/react/pull/14569)) +* Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/facebook/react/pull/14594) in [#14594](https://github.com/facebook/react/pull/14594)) * Support synchronous thenables passed to `React.lazy()`. ([@gaearon](https://github.com/gaearon) in [#14626](https://github.com/facebook/react/pull/14626)) +* Render components with Hooks twice in Strict Mode (DEV-only) to match class behavior. ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) +* Warn about mismatching Hook order in development. ([@threepointone](https://github.com/threepointone) in [#14585](https://github.com/facebook/react/pull/14585) and [@acdlite](https://github.com/acdlite) in [#14591](https://github.com/facebook/react/pull/14591)) ### React Test Renderer * Support Hooks in the shallow renderer. ([@trueadm](https://github.com/trueadm) in [#14567](https://github.com/facebook/react/pull/14567)) -* Fix shallow renderer passing incorrect state to `shouldComponentUpdate` in the presence of `getDerivedStateFromProps`. ([@chenesan](https://github.com/chenesan) in [#14613](https://github.com/facebook/react/pull/14613)) +* Fix wrong state in `shouldComponentUpdate` in the presence of `getDerivedStateFromProps` for Shallow Renderer. ([@chenesan](https://github.com/chenesan) in [#14613](https://github.com/facebook/react/pull/14613)) ### ESLint Plugin: React Hooks * Initial [release](https://www.npmjs.com/package/eslint-plugin-react-hooks). ([@calebmer](https://github.com/calebmer) in [#13968](https://github.com/facebook/react/pull/13968)) * Fix reporting after encountering a loop. ([@calebmer](https://github.com/calebmer) and [@Yurickh](https://github.com/Yurickh) in [#13968](https://github.com/facebook/react/pull/13968)) - +* Don't consider throwing to be a rule violation. ([@sophiebits](https://github.com/sophiebits) in [#14040](https://github.com/facebook/react/pull/14040)) From e9081c7f750939ae00fe799dd78ff005f336ccc4 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 29 Jan 2019 17:58:12 +0000 Subject: [PATCH 08/26] Update and rename 2019-01-30-react-v16.8.0.md to 2019-02-04-react-v16.8.0.md --- ...{2019-01-30-react-v16.8.0.md => 2019-02-04-react-v16.8.0.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename content/blog/{2019-01-30-react-v16.8.0.md => 2019-02-04-react-v16.8.0.md} (97%) diff --git a/content/blog/2019-01-30-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md similarity index 97% rename from content/blog/2019-01-30-react-v16.8.0.md rename to content/blog/2019-02-04-react-v16.8.0.md index 84412abe..efcb17e9 100644 --- a/content/blog/2019-01-30-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -86,7 +86,7 @@ Refer to the documentation for [detailed installation instructions](/docs/instal ### React DOM * Bail out of rendering on identical values for `useState` and `useReducer` Hooks. ([@acdlite](https://github.com/acdlite) in [#14569](https://github.com/facebook/react/pull/14569)) -* Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/facebook/react/pull/14594) in [#14594](https://github.com/facebook/react/pull/14594)) +* Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/acdlite) in [#14594](https://github.com/facebook/react/pull/14594)) * Support synchronous thenables passed to `React.lazy()`. ([@gaearon](https://github.com/gaearon) in [#14626](https://github.com/facebook/react/pull/14626)) * Render components with Hooks twice in Strict Mode (DEV-only) to match class behavior. ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) * Warn about mismatching Hook order in development. ([@threepointone](https://github.com/threepointone) in [#14585](https://github.com/facebook/react/pull/14585) and [@acdlite](https://github.com/acdlite) in [#14591](https://github.com/facebook/react/pull/14591)) From d15ec6e630810e9caa64b7e85546a6a8d8238b15 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Feb 2019 15:35:36 +0000 Subject: [PATCH 09/26] changelog updates --- content/blog/2019-02-04-react-v16.8.0.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index efcb17e9..fa2bf4f7 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -81,7 +81,8 @@ Refer to the documentation for [detailed installation instructions](/docs/instal ### React -* Adds [Hooks](https://reactjs.org/docs/hooks-intro.html) — a way to use state and other React features without writing a class. ([@acdlite](https://github.com/acdlite) et al. in [#13968](https://github.com/facebook/react/pull/13968)) +* Add [Hooks](https://reactjs.org/docs/hooks-intro.html) — a way to use state and other React features without writing a class. ([@acdlite](https://github.com/acdlite) et al. in [#13968](https://github.com/facebook/react/pull/13968)) +* Improve the `useReducer` Hook lazy initialization API. ([@acdlite](https://github.com/acdlite) in [#14723](https://github.com/facebook/react/pull/14723)) ### React DOM @@ -99,5 +100,5 @@ Refer to the documentation for [detailed installation instructions](/docs/instal ### ESLint Plugin: React Hooks * Initial [release](https://www.npmjs.com/package/eslint-plugin-react-hooks). ([@calebmer](https://github.com/calebmer) in [#13968](https://github.com/facebook/react/pull/13968)) -* Fix reporting after encountering a loop. ([@calebmer](https://github.com/calebmer) and [@Yurickh](https://github.com/Yurickh) in [#13968](https://github.com/facebook/react/pull/13968)) +* Fix reporting after encountering a loop. ([@calebmer](https://github.com/calebmer) and [@Yurickh](https://github.com/Yurickh) in [#14661](https://github.com/facebook/react/pull/14661)) * Don't consider throwing to be a rule violation. ([@sophiebits](https://github.com/sophiebits) in [#14040](https://github.com/facebook/react/pull/14040)) From 37d46dd8a397512ca3078aa1f320af27f9bf747c Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Feb 2019 16:54:14 +0000 Subject: [PATCH 10/26] review tweaks --- content/blog/2019-02-04-react-v16.8.0.md | 57 +++++++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index fa2bf4f7..5731a12e 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -38,7 +38,7 @@ Note that **to enable Hooks, all React packages need to be 16.8.0 or higher**. H ## Tooling Support -React Hooks are now fully supported by React DevTools. They are also supported in the latest Flow and TypeScript definitions for React. We recommend using a new [lint rule](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce best practices with Hooks. It will soon be included into Create React App by default. +React Hooks are now fully supported by React DevTools. They are also supported in the latest Flow and TypeScript definitions for React. We strongly recommend enabling a new [lint rule called `eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce best practices with Hooks. It will soon be included into Create React App by default. ## What's Next @@ -46,14 +46,35 @@ We described our plan for the next months in the recently published [React Roadm Note that React Hooks don't cover *all* use cases for classes yet but they're [very close](/docs/hooks-faq.html#do-hooks-cover-all-use-cases-for-classes). Currently, only `getSnapshotBeforeUpdate()` and `componentDidCatch()` methods don't have equivalent Hooks APIs, and these lifecycles are relatively uncommon. If you want, you should be able to use Hooks in most of the new code you're writing. -Even while Hooks were in alpha, we saw many [interesting examples](https://medium.com/@drcmda/hooks-in-react-spring-a-tutorial-c6c436ad7ee4) of custom Hooks for animations, forms, subscriptions, integrating with other libraries, and so on. Our goal is to empower the React community to write components and Hooks that deliver great user and developer experience. We can't wait to see what you'll create next! +Even while Hooks were in alpha, we saw many [interesting examples](https://medium.com/@drcmda/hooks-in-react-spring-a-tutorial-c6c436ad7ee4) of custom Hooks for animations, forms, subscriptions, integrating with other libraries, and so on. We're excited about Hooks because they make code reuse easier, helping you write your components in a simpler way and make great user experiences. We can't wait to see what you'll create next! ## Thanks We'd like to thank everybody who commented on the [Hooks RFC](https://github.com/reactjs/rfcs/pull/68) for sharing their feedback. We've read all of your comments and made some adjustments to the final API based on them. +## Breaking Changes from Alpha Versions + +React 16.8.0 is the first **stable** release supporting Hooks. + +Over the past few months, we have also provided several **alpha** versions for community feedback: `16.7.0-alpha.0`, `16.7.0-alpha.1`, `16.7.0-alpha.2`, and `16.8.0-alpha.0`. + +**We don't recommend depending on alphas in production code.** We publish them so we can make breaking changes in response to community feedback before the API is stable. + +Here is a list of all breaking changes to Hooks between the first alpha and the stable release: + +* Remove `useMutationEffect`. ([@sophiebits](https://github.com/sophiebits) in [#14336](https://github.com/facebook/react/pull/14336)) +* Rename `useImperativeMethods` to `useImperativeHandle`. ([@threepointone](https://github.com/threepointone) in [#14565](https://github.com/facebook/react/pull/14565)) +* Bail out of rendering on identical values for `useState` and `useReducer` Hooks. ([@acdlite](https://github.com/acdlite) in [#14569](https://github.com/facebook/react/pull/14569)) +* Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/acdlite) in [#14594](https://github.com/facebook/react/pull/14594)) +* Render components with Hooks twice in Strict Mode (DEV-only). ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) +* Improve the `useReducer` Hook lazy initialization API. ([@acdlite](https://github.com/acdlite) in [#14723](https://github.com/facebook/react/pull/14723)) + +Read more about our [versioning policy and commitment to stability](/docs/faq-versioning.html). + ## Installation +### React + React v16.8.0 is available on the npm registry. To install React 16 with Yarn, run: @@ -77,6 +98,37 @@ We also provide UMD builds of React via a CDN: Refer to the documentation for [detailed installation instructions](/docs/installation.html). +### ESLint Plugin for React Hooks + +>Note +> +>If you're using Create React App, instead of manually configuring ESLint you can wait for the next version of `react-scripts` which will come out shortly and will include this rule. + +Assuming you already have ESLint installed, run: + +```sh +# npm +npm install eslint-plugin-react-hooks@next --save-dev + +# yarn +yarn add eslint-plugin-react-hooks@next --dev +``` + +Then add it to your ESLint configuration: + +```js +{ + "plugins": [ + // ... + "react-hooks" + ], + "rules": { + // ... + "react-hooks/rules-of-hooks": "error" + } +} +``` + ## Changelog ### React @@ -92,6 +144,7 @@ Refer to the documentation for [detailed installation instructions](/docs/instal * Render components with Hooks twice in Strict Mode (DEV-only) to match class behavior. ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) * Warn about mismatching Hook order in development. ([@threepointone](https://github.com/threepointone) in [#14585](https://github.com/facebook/react/pull/14585) and [@acdlite](https://github.com/acdlite) in [#14591](https://github.com/facebook/react/pull/14591)) + ### React Test Renderer * Support Hooks in the shallow renderer. ([@trueadm](https://github.com/trueadm) in [#14567](https://github.com/facebook/react/pull/14567)) From ee5fea9f36c9e6cbeaff0b494160a180dd27075f Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Feb 2019 17:06:32 +0000 Subject: [PATCH 11/26] Mention type defs --- content/blog/2019-02-04-react-v16.8.0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index 5731a12e..7a8bdd09 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -36,6 +36,8 @@ Note that **to enable Hooks, all React packages need to be 16.8.0 or higher**. H **React Native will fully support Hooks in its next stable release.** +The final TypeScript and Flow definitions are currently in review and will be available soon. + ## Tooling Support React Hooks are now fully supported by React DevTools. They are also supported in the latest Flow and TypeScript definitions for React. We strongly recommend enabling a new [lint rule called `eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce best practices with Hooks. It will soon be included into Create React App by default. From e3012392a3107aa47d65029a17d47721205b6db2 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 1 Feb 2019 19:55:03 +0000 Subject: [PATCH 12/26] add warning for invalid hook call --- content/warnings/invalid-hook-call-warning.md | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 content/warnings/invalid-hook-call-warning.md diff --git a/content/warnings/invalid-hook-call-warning.md b/content/warnings/invalid-hook-call-warning.md new file mode 100644 index 00000000..176c7b2a --- /dev/null +++ b/content/warnings/invalid-hook-call-warning.md @@ -0,0 +1,121 @@ +--- +title: Invalid Hook Call Warning +layout: single +permalink: warnings/invalid-hook-call-warning.html +--- + + You are probably here because you got the following error message: + + > Hooks can only be called inside the body of a function component. + +There are three common reasons you might be seeing it: + +1. You might have **mismatching versions** of React and React DOM. +2. You might be **breaking the [Rules of Hooks](/docs/hooks-rules.html)**. +3. You might have **more than one copy of React** in the same app. + +Let's look at each of these cases. + +## Mismatching Versions of React and React DOM + +You might be using a version of `react-dom` (<= 16.8.0) or `react-native` (<= 0.60) that doesn't yet support Hooks. You can run `npm ls react-dom` or `npm ls react-native` in your application folder to check which version you're using. If you find more than one of them, this might also create problems (more on that below). + +## Breaking the Rules of Hooks + +You can only call Hooks **while React is rendering a function component**: + +* ✅ Call them at the top level in the body of a function component. +* ✅ Call them at the top level in the body of a [custom Hook](/docs/hooks-custom.html). + +**Learn more about this in the [Rules of Hooks](/docs/hooks-rules.html).** + +To avoid confusion, it’s **not** supported to call Hooks in other cases: + +* 🔴 Do not call Hooks in class components. +* 🔴 Do not call in event handlers. +* 🔴 Do not call Hooks inside functions passed to `useMemo`, `useReducer`, or `useEffect`. + +If you break these rules, you might see this error. + +```js{2-3,8-9,15-16,23-24,33-34} +function Counter() { + // ✅ Good: top-level in a function component + const [count, setCount] = useState(0); + // ... +} + +function useWindowWidth() { + // ✅ Good: top-level in a custom Hook + const [width, setWidth] = useState(window.innerWidth); + // ... +} + +function Bad1() { + function handleClick() { + // 🔴 Bad: inside an event handler (to fix, move it outside!) + const theme = useContext(ThemeContext); + } + // ... +} + +function Bad2() { + const style = useMemo(() => { + // 🔴 Bad: inside useMemo (to fix, move it outside!) + const theme = useContext(ThemeContext); + return createStyle(theme); + }); + // ... +} + + +class Bad3 extends React.Component { + render() { + // 🔴 Bad: inside a class component + useEffect(() => {}) + // ... + } +} +``` + +You can use the [`eslint-plugin-react-hooks` plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to catch some of these mistakes. + +>Note +> +>[Custom Hooks](/docs/hooks-custom.html) *may* call other Hooks (that's their whole purpose). This works because custom Hooks are also supposed to only be called while a function component is rendering. + + +## Duplicate React + +In order for Hooks to work, `react` import from your application code needs to resolve to the same module as the `react` import from inside the `react-dom` package. + +If these `react` imports resolve to two different exports objects, you will see this warning. This may happen if you **accidentally end up with two copies** of the `react` package. + +If you use Node for package management, you can run this check in your project folder: + + npm ls react + +If you see more than one React, you'll need to figure out why this happens, and fix your dependency tree. For example, maybe a library you're using incorrectly specifies `react` as a dependency (rather than a peer dependency). Until such a library is fixed, [Yarn resolutions](https://yarnpkg.com/lang/en/docs/selective-version-resolutions/) is one possible workaround. + +You can also try to debug this problem by adding some logs and restarting your development server: + +```js +// Add this in node_modules/react-dom/index.js +window.React1 = require('react'); + +// Add this in your component file +require('react-dom'); +window.React2 = require('react'); +console.log(window.React1 === window.React2); +``` + +If it prints `false` then you might have two Reacts and need to figure out why that happened. [This issue](https://github.com/facebook/react/issues/13991) includes some common reasons encountered by the community. + +This problem can also come up when you use `npm link` or an equivalent. In that case, your bundler might "see" two Reacts — one in application folder and one in your library folder. Assuming `myapp` and `mylib` are sibling folders, one possible fix is to run `npm link ../myapp/node_modules/react` from `mylib`. This should make the library use the application's React copy. + +>Note +> +>In general, React supports using multiple independent copies on one page (for example, if an app and a third-party widget both use it). It only breaks if you call `ReactDOM.render()` for a component with a different `require('react')` than seen by `react-dom`. + +## Other Causes + +If none of this worked, please comment in [this issue](https://github.com/facebook/react/issues/13991) and we'll try to help. Try to create a small reproducing example — you might discover the problem as you're doing it. From 2fd487e3093319b14c3e031d596ebc4e96a480a8 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 4 Feb 2019 14:09:46 +0000 Subject: [PATCH 13/26] Update 2019-02-04-react-v16.8.0.md --- content/blog/2019-02-04-react-v16.8.0.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index 7a8bdd09..688890d9 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -21,7 +21,7 @@ If you've never heard of Hooks before, you might find these resources interestin ## No Big Rewrites -We don't recommend rewriting your existing applications to use Hooks overnight. Instead, try using Hooks in some of the new components, and let us know what you think. Code using Hooks will work [side by side](/docs/hooks-intro.html#gradual-adoption-strategy) with your existing code using classes. +We don't recommend rewriting your existing applications to use Hooks overnight. Instead, try using Hooks in some of the new components, and let us know what you think. Code using Hooks will work [side by side](/docs/hooks-intro.html#gradual-adoption-strategy) with existing code using classes. ## Can I Use Hooks Today? @@ -34,13 +34,13 @@ Yes! Starting with 16.8.0, React includes a stable implementation of React Hooks Note that **to enable Hooks, all React packages need to be 16.8.0 or higher**. Hooks won't work if you forget to update, for example, React DOM. -**React Native will fully support Hooks in its next stable release.** +**React Native will support Hooks in the [0.60 release](https://github.com/react-native-community/react-native-releases/issues/79#issuecomment-457735214).** -The final TypeScript and Flow definitions are currently in review and will be available soon. +The latest TypeScript and Flow definitions for React support Hooks. The Flow definitions will be updated to the final `useReducer` API in the next Flow release. ## Tooling Support -React Hooks are now fully supported by React DevTools. They are also supported in the latest Flow and TypeScript definitions for React. We strongly recommend enabling a new [lint rule called `eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce best practices with Hooks. It will soon be included into Create React App by default. +React Hooks are now supported by React DevTools. They are also supported in the latest Flow and TypeScript definitions for React. We strongly recommend enabling a new [lint rule called `eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce best practices with Hooks. It will soon be included into Create React App by default. ## What's Next @@ -58,7 +58,7 @@ We'd like to thank everybody who commented on the [Hooks RFC](https://github.com React 16.8.0 is the first **stable** release supporting Hooks. -Over the past few months, we have also provided several **alpha** versions for community feedback: `16.7.0-alpha.0`, `16.7.0-alpha.1`, `16.7.0-alpha.2`, and `16.8.0-alpha.0`. +Over the past few months, we have also provided several **alpha** versions for community feedback: `16.7.0-alpha.0`, `16.7.0-alpha.2`, and `16.8.0-alpha.0`. **We don't recommend depending on alphas in production code.** We publish them so we can make breaking changes in response to community feedback before the API is stable. @@ -68,6 +68,7 @@ Here is a list of all breaking changes to Hooks between the first alpha and the * Rename `useImperativeMethods` to `useImperativeHandle`. ([@threepointone](https://github.com/threepointone) in [#14565](https://github.com/facebook/react/pull/14565)) * Bail out of rendering on identical values for `useState` and `useReducer` Hooks. ([@acdlite](https://github.com/acdlite) in [#14569](https://github.com/facebook/react/pull/14569)) * Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/acdlite) in [#14594](https://github.com/facebook/react/pull/14594)) +* Use `Object.is` algorithm for comparing `useState` and `useReducer` values. ([@Jessidhia](https://github.com/Jessidhia) in [#14752](https://github.com/facebook/react/pull/14752)) * Render components with Hooks twice in Strict Mode (DEV-only). ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) * Improve the `useReducer` Hook lazy initialization API. ([@acdlite](https://github.com/acdlite) in [#14723](https://github.com/facebook/react/pull/14723)) @@ -142,6 +143,7 @@ Then add it to your ESLint configuration: * Bail out of rendering on identical values for `useState` and `useReducer` Hooks. ([@acdlite](https://github.com/acdlite) in [#14569](https://github.com/facebook/react/pull/14569)) * Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/acdlite) in [#14594](https://github.com/facebook/react/pull/14594)) +* Use `Object.is` algorithm for comparing `useState` and `useReducer` values. ([@Jessidhia](https://github.com/Jessidhia) in [#14752](https://github.com/facebook/react/pull/14752)) * Support synchronous thenables passed to `React.lazy()`. ([@gaearon](https://github.com/gaearon) in [#14626](https://github.com/facebook/react/pull/14626)) * Render components with Hooks twice in Strict Mode (DEV-only) to match class behavior. ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) * Warn about mismatching Hook order in development. ([@threepointone](https://github.com/threepointone) in [#14585](https://github.com/facebook/react/pull/14585) and [@acdlite](https://github.com/acdlite) in [#14591](https://github.com/facebook/react/pull/14591)) From ed6e711a83f3f53f834fb5e331632a0dd20c3e95 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 4 Feb 2019 14:13:21 +0000 Subject: [PATCH 14/26] Thanks Sophie --- content/blog/2019-02-04-react-v16.8.0.md | 36 +++++++++++------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index 688890d9..a2c13415 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -54,26 +54,6 @@ Even while Hooks were in alpha, we saw many [interesting examples](https://mediu We'd like to thank everybody who commented on the [Hooks RFC](https://github.com/reactjs/rfcs/pull/68) for sharing their feedback. We've read all of your comments and made some adjustments to the final API based on them. -## Breaking Changes from Alpha Versions - -React 16.8.0 is the first **stable** release supporting Hooks. - -Over the past few months, we have also provided several **alpha** versions for community feedback: `16.7.0-alpha.0`, `16.7.0-alpha.2`, and `16.8.0-alpha.0`. - -**We don't recommend depending on alphas in production code.** We publish them so we can make breaking changes in response to community feedback before the API is stable. - -Here is a list of all breaking changes to Hooks between the first alpha and the stable release: - -* Remove `useMutationEffect`. ([@sophiebits](https://github.com/sophiebits) in [#14336](https://github.com/facebook/react/pull/14336)) -* Rename `useImperativeMethods` to `useImperativeHandle`. ([@threepointone](https://github.com/threepointone) in [#14565](https://github.com/facebook/react/pull/14565)) -* Bail out of rendering on identical values for `useState` and `useReducer` Hooks. ([@acdlite](https://github.com/acdlite) in [#14569](https://github.com/facebook/react/pull/14569)) -* Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/acdlite) in [#14594](https://github.com/facebook/react/pull/14594)) -* Use `Object.is` algorithm for comparing `useState` and `useReducer` values. ([@Jessidhia](https://github.com/Jessidhia) in [#14752](https://github.com/facebook/react/pull/14752)) -* Render components with Hooks twice in Strict Mode (DEV-only). ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) -* Improve the `useReducer` Hook lazy initialization API. ([@acdlite](https://github.com/acdlite) in [#14723](https://github.com/facebook/react/pull/14723)) - -Read more about our [versioning policy and commitment to stability](/docs/faq-versioning.html). - ## Installation ### React @@ -159,3 +139,19 @@ Then add it to your ESLint configuration: * Initial [release](https://www.npmjs.com/package/eslint-plugin-react-hooks). ([@calebmer](https://github.com/calebmer) in [#13968](https://github.com/facebook/react/pull/13968)) * Fix reporting after encountering a loop. ([@calebmer](https://github.com/calebmer) and [@Yurickh](https://github.com/Yurickh) in [#14661](https://github.com/facebook/react/pull/14661)) * Don't consider throwing to be a rule violation. ([@sophiebits](https://github.com/sophiebits) in [#14040](https://github.com/facebook/react/pull/14040)) + +## Hooks Changelog Since Alpha Versions + +The above changelog contains all notable changes since our last **stable** release (16.7.0). [As with all our minor releases](/docs/faq-versioning.html), none of the changes break backwards compatibility. + +If you're currently using Hooks from an alpha build of React, note that this release does contain some small breaking changes to Hooks. **We don't recommend depending on alphas in production code.** We publish them so we can make changes in response to community feedback before the API is stable. + +Here are all breaking changes to Hooks that have been made since the first alpha release: + +* Remove `useMutationEffect`. ([@sophiebits](https://github.com/sophiebits) in [#14336](https://github.com/facebook/react/pull/14336)) +* Rename `useImperativeMethods` to `useImperativeHandle`. ([@threepointone](https://github.com/threepointone) in [#14565](https://github.com/facebook/react/pull/14565)) +* Bail out of rendering on identical values for `useState` and `useReducer` Hooks. ([@acdlite](https://github.com/acdlite) in [#14569](https://github.com/facebook/react/pull/14569)) +* Don’t compare the first argument passed to `useEffect`/`useMemo`/`useCallback` Hooks. ([@acdlite](https://github.com/acdlite) in [#14594](https://github.com/facebook/react/pull/14594)) +* Use `Object.is` algorithm for comparing `useState` and `useReducer` values. ([@Jessidhia](https://github.com/Jessidhia) in [#14752](https://github.com/facebook/react/pull/14752)) +* Render components with Hooks twice in Strict Mode (DEV-only). ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) +* Improve the `useReducer` Hook lazy initialization API. ([@acdlite](https://github.com/acdlite) in [#14723](https://github.com/facebook/react/pull/14723)) From 0d8957026442f2af82190874213d0935685dc42b Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 4 Feb 2019 14:14:14 +0000 Subject: [PATCH 15/26] Update 2019-02-04-react-v16.8.0.md --- content/blog/2019-02-04-react-v16.8.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index a2c13415..6591b440 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -84,6 +84,7 @@ Refer to the documentation for [detailed installation instructions](/docs/instal ### ESLint Plugin for React Hooks >Note +>As mentioned above, we strongly recommend using the `eslint-plugin-react-hooks` lint rule. > >If you're using Create React App, instead of manually configuring ESLint you can wait for the next version of `react-scripts` which will come out shortly and will include this rule. From 95258c051661ee21c7f7dd3d9e17c0d3d9eb67b0 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 4 Feb 2019 14:26:21 +0000 Subject: [PATCH 16/26] Revert "add warning for invalid hook call" This reverts commit e3012392a3107aa47d65029a17d47721205b6db2. --- content/warnings/invalid-hook-call-warning.md | 121 ------------------ 1 file changed, 121 deletions(-) delete mode 100644 content/warnings/invalid-hook-call-warning.md diff --git a/content/warnings/invalid-hook-call-warning.md b/content/warnings/invalid-hook-call-warning.md deleted file mode 100644 index 176c7b2a..00000000 --- a/content/warnings/invalid-hook-call-warning.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: Invalid Hook Call Warning -layout: single -permalink: warnings/invalid-hook-call-warning.html ---- - - You are probably here because you got the following error message: - - > Hooks can only be called inside the body of a function component. - -There are three common reasons you might be seeing it: - -1. You might have **mismatching versions** of React and React DOM. -2. You might be **breaking the [Rules of Hooks](/docs/hooks-rules.html)**. -3. You might have **more than one copy of React** in the same app. - -Let's look at each of these cases. - -## Mismatching Versions of React and React DOM - -You might be using a version of `react-dom` (<= 16.8.0) or `react-native` (<= 0.60) that doesn't yet support Hooks. You can run `npm ls react-dom` or `npm ls react-native` in your application folder to check which version you're using. If you find more than one of them, this might also create problems (more on that below). - -## Breaking the Rules of Hooks - -You can only call Hooks **while React is rendering a function component**: - -* ✅ Call them at the top level in the body of a function component. -* ✅ Call them at the top level in the body of a [custom Hook](/docs/hooks-custom.html). - -**Learn more about this in the [Rules of Hooks](/docs/hooks-rules.html).** - -To avoid confusion, it’s **not** supported to call Hooks in other cases: - -* 🔴 Do not call Hooks in class components. -* 🔴 Do not call in event handlers. -* 🔴 Do not call Hooks inside functions passed to `useMemo`, `useReducer`, or `useEffect`. - -If you break these rules, you might see this error. - -```js{2-3,8-9,15-16,23-24,33-34} -function Counter() { - // ✅ Good: top-level in a function component - const [count, setCount] = useState(0); - // ... -} - -function useWindowWidth() { - // ✅ Good: top-level in a custom Hook - const [width, setWidth] = useState(window.innerWidth); - // ... -} - -function Bad1() { - function handleClick() { - // 🔴 Bad: inside an event handler (to fix, move it outside!) - const theme = useContext(ThemeContext); - } - // ... -} - -function Bad2() { - const style = useMemo(() => { - // 🔴 Bad: inside useMemo (to fix, move it outside!) - const theme = useContext(ThemeContext); - return createStyle(theme); - }); - // ... -} - - -class Bad3 extends React.Component { - render() { - // 🔴 Bad: inside a class component - useEffect(() => {}) - // ... - } -} -``` - -You can use the [`eslint-plugin-react-hooks` plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to catch some of these mistakes. - ->Note -> ->[Custom Hooks](/docs/hooks-custom.html) *may* call other Hooks (that's their whole purpose). This works because custom Hooks are also supposed to only be called while a function component is rendering. - - -## Duplicate React - -In order for Hooks to work, `react` import from your application code needs to resolve to the same module as the `react` import from inside the `react-dom` package. - -If these `react` imports resolve to two different exports objects, you will see this warning. This may happen if you **accidentally end up with two copies** of the `react` package. - -If you use Node for package management, you can run this check in your project folder: - - npm ls react - -If you see more than one React, you'll need to figure out why this happens, and fix your dependency tree. For example, maybe a library you're using incorrectly specifies `react` as a dependency (rather than a peer dependency). Until such a library is fixed, [Yarn resolutions](https://yarnpkg.com/lang/en/docs/selective-version-resolutions/) is one possible workaround. - -You can also try to debug this problem by adding some logs and restarting your development server: - -```js -// Add this in node_modules/react-dom/index.js -window.React1 = require('react'); - -// Add this in your component file -require('react-dom'); -window.React2 = require('react'); -console.log(window.React1 === window.React2); -``` - -If it prints `false` then you might have two Reacts and need to figure out why that happened. [This issue](https://github.com/facebook/react/issues/13991) includes some common reasons encountered by the community. - -This problem can also come up when you use `npm link` or an equivalent. In that case, your bundler might "see" two Reacts — one in application folder and one in your library folder. Assuming `myapp` and `mylib` are sibling folders, one possible fix is to run `npm link ../myapp/node_modules/react` from `mylib`. This should make the library use the application's React copy. - ->Note -> ->In general, React supports using multiple independent copies on one page (for example, if an app and a third-party widget both use it). It only breaks if you call `ReactDOM.render()` for a component with a different `require('react')` than seen by `react-dom`. - -## Other Causes - -If none of this worked, please comment in [this issue](https://github.com/facebook/react/issues/13991) and we'll try to help. Try to create a small reproducing example — you might discover the problem as you're doing it. From e5a987bc60a80ca935f8e11f16b06f2a58215b64 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 4 Feb 2019 14:34:52 +0000 Subject: [PATCH 17/26] Tweaks --- content/blog/2019-02-04-react-v16.8.0.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index 6591b440..0cd4ae89 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -36,8 +36,6 @@ Note that **to enable Hooks, all React packages need to be 16.8.0 or higher**. H **React Native will support Hooks in the [0.60 release](https://github.com/react-native-community/react-native-releases/issues/79#issuecomment-457735214).** -The latest TypeScript and Flow definitions for React support Hooks. The Flow definitions will be updated to the final `useReducer` API in the next Flow release. - ## Tooling Support React Hooks are now supported by React DevTools. They are also supported in the latest Flow and TypeScript definitions for React. We strongly recommend enabling a new [lint rule called `eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) to enforce best practices with Hooks. It will soon be included into Create React App by default. @@ -84,6 +82,7 @@ Refer to the documentation for [detailed installation instructions](/docs/instal ### ESLint Plugin for React Hooks >Note +> >As mentioned above, we strongly recommend using the `eslint-plugin-react-hooks` lint rule. > >If you're using Create React App, instead of manually configuring ESLint you can wait for the next version of `react-scripts` which will come out shortly and will include this rule. From d460a9b106c7b45d1f0168dbbeafb245ccd16cab Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 4 Feb 2019 15:34:23 +0000 Subject: [PATCH 18/26] Docs updates --- content/docs/hooks-faq.md | 17 +++++++++ content/docs/hooks-reference.md | 67 +++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index db403bc0..91c69529 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -37,6 +37,7 @@ This page answers some of the frequently asked questions about [Hooks](/docs/hoo * [Can I run an effect only on updates?](#can-i-run-an-effect-only-on-updates) * [How to get the previous props or state?](#how-to-get-the-previous-props-or-state) * [How do I implement getDerivedStateFromProps?](#how-do-i-implement-getderivedstatefromprops) + * [Is there something like forceUpdate?](#is-there-something-like-forceupdate) * [Can I make a ref to a function component?](#can-i-make-a-ref-to-a-function-component) * [What does const [thing, setThing] = useState() mean?](#what-does-const-thing-setthing--usestate-mean) * **[Performance Optimizations](#performance-optimizations)** @@ -322,6 +323,22 @@ function ScrollView({row}) { This might look strange at first, but an update during rendering is exactly what `getDerivedStateFromProps` has always been like conceptually. +### Is there something like forceUpdate? + +Both `useState` and `useReducer` Hooks [bail out of updates](/docs/hooks-reference.html#bailing-out-of-a-state-update) if the next value is the same as the previous one. Mutating state in place and calling `setState` will not cause a re-render. + +Normally, you shouldn't mutate local state in React. However, as an escape hatch, you can use an incrementing counter to force a re-render even if the state has not changed: + +```js + const [ignored, forceUpdate] = useReducer(x => x + 1, 0); + + function handleClick() { + forceUpdate(); + } +``` + +Try to avoid this pattern if possible. + ### Can I make a ref to a function component? While you shouldn't need this often, you may expose some imperative methods to a parent component with the [`useImperativeHandle`](/docs/hooks-reference.html#useimperativehandle) Hook. diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index 5dd1c75f..cddd0277 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -89,6 +89,10 @@ const [state, setState] = useState(() => { }); ``` +#### Bailing out of a state update + +If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the [`Object.is` comparison algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).) + ### `useEffect` ```js @@ -172,20 +176,18 @@ The following Hooks are either variants of the basic ones from the previous sect ### `useReducer` ```js -const [state, dispatch] = useReducer(reducer, initialState); +const [state, dispatch] = useReducer(reducer, initialArg, init); ``` An alternative to [`useState`](#usestate). Accepts a reducer of type `(state, action) => newState`, and returns the current state paired with a `dispatch` method. (If you're familiar with Redux, you already know how this works.) +`useReducer` is usually preferable to `useState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. `useReducer` also lets you optimize performance for components that trigger deep updates because [you can pass `dispatch` down instead of callbacks](/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down). + Here's the counter example from the [`useState`](#usestate) section, rewritten to use a reducer: ```js -const initialState = {count: 0}; - function reducer(state, action) { switch (action.type) { - case 'reset': - return initialState; case 'increment': return {count: state.count + 1}; case 'decrement': @@ -202,9 +204,6 @@ function Counter({initialCount}) { return ( <> Count: {state.count} - @@ -212,21 +211,52 @@ function Counter({initialCount}) { } ``` +#### Specifying the initial state + +There’s a few different ways to initialize `useReducer` state. You may choose either one depending on the use case. The simplest way to pass the initial state as a second argument: + +```js{3} + const [state, dispatch] = useReducer( + reducer, + {count: initialCount} + ); +``` + +>Note +> +>React doesn’t use the `state = initialState` argument convention popularized by Redux. The initial value sometimes needs to depend on props and so is specified from the Hook call instead. If you feel strongly about this, you can write `state = initialState` both in the reducer and inside the `useReducer` destructuring assignment, but it's not encouraged. + #### Lazy initialization -`useReducer` accepts an optional third argument, `initialAction`. If provided, the initial action is applied during the initial render. This is useful for computing an initial state that includes values passed via props: +If calculating the initial state is expensive, you can initialize it lazily. In that case, you can skip the second argument (and pass `undefined`). The third `useReducer` argument is an optional `init` function that you can provide to calculate the initial value once: -```js -const initialState = {count: 0}; +```js{3-4} + const [state, dispatch] = useReducer( + reducer, + undefined, + () => ({count: initialCount}) + ); +``` + +#### Lazy initialization with a transform + +For the most flexibility, you can specify *both* the second `initialArg` and the third `init` function arguments. In that case, the initial state will be set to `init(initialArg)`. + +This is handy if you want to extract the lazy initialization logic outside your reducer: + +```js{1-3,11-12,21,26} +function init(initialCount) { + return {count: initialCount}; +} function reducer(state, action) { switch (action.type) { - case 'reset': - return {count: action.payload}; case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; + case 'reset': + return init(action.payload); default: // A reducer must always return a valid state. // Alternatively you can throw an error if an invalid action is dispatched. @@ -235,12 +265,7 @@ function reducer(state, action) { } function Counter({initialCount}) { - const [state, dispatch] = useReducer( - reducer, - initialState, - {type: 'reset', payload: initialCount}, - ); - + const [state, dispatch] = useReducer(reducer, initialCount, init); return ( <> Count: {state.count} @@ -255,7 +280,9 @@ function Counter({initialCount}) { } ``` -`useReducer` is usually preferable to `useState` when you have complex state logic that involves multiple sub-values. It also lets you optimize performance for components that trigger deep updates because [you can pass `dispatch` down instead of callbacks](/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down). +#### Bailing out of a dispatch + +If you return the same value from a Reducer Hook as the current state, React will bail out without rendering the children or firing effects. (React uses the [`Object.is` comparison algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).) ### `useCallback` From f9f0d66272a373d52ea975978c0c3b2b77620bd8 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 5 Feb 2019 15:24:15 +0000 Subject: [PATCH 19/26] Point to codesandbox and usehooks as community examples --- content/blog/2019-02-04-react-v16.8.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index 0cd4ae89..f518ddde 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -46,7 +46,7 @@ We described our plan for the next months in the recently published [React Roadm Note that React Hooks don't cover *all* use cases for classes yet but they're [very close](/docs/hooks-faq.html#do-hooks-cover-all-use-cases-for-classes). Currently, only `getSnapshotBeforeUpdate()` and `componentDidCatch()` methods don't have equivalent Hooks APIs, and these lifecycles are relatively uncommon. If you want, you should be able to use Hooks in most of the new code you're writing. -Even while Hooks were in alpha, we saw many [interesting examples](https://medium.com/@drcmda/hooks-in-react-spring-a-tutorial-c6c436ad7ee4) of custom Hooks for animations, forms, subscriptions, integrating with other libraries, and so on. We're excited about Hooks because they make code reuse easier, helping you write your components in a simpler way and make great user experiences. We can't wait to see what you'll create next! +Even while Hooks were in alpha, the React community created many interesting [examples](https://codesandbox.io/react-hooks) and [recipes](https://usehooks.com) using Hooks for animations, forms, subscriptions, integrating with other libraries, and so on. We're excited about Hooks because they make code reuse easier, helping you write your components in a simpler way and make great user experiences. We can't wait to see what you'll create next! ## Thanks From d97cdcac7f3166c753928beb88209f1face6ac01 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 5 Feb 2019 16:05:05 +0000 Subject: [PATCH 20/26] tweaks --- content/docs/hooks-reference.md | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index cddd0277..6a8d8a66 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -78,7 +78,7 @@ The "+" and "-" buttons use the functional form, because the updated value is ba > > Another option is `useReducer`, which is more suited for managing state objects that contain multiple sub-values. -#### Lazy initialization +#### Lazy initial state The `initialState` argument is the state used during the initial render. In subsequent renders, it is disregarded. If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render: @@ -186,6 +186,8 @@ An alternative to [`useState`](#usestate). Accepts a reducer of type `(state, ac Here's the counter example from the [`useState`](#usestate) section, rewritten to use a reducer: ```js +const initialState = {count: 0}; + function reducer(state, action) { switch (action.type) { case 'increment': @@ -193,14 +195,12 @@ function reducer(state, action) { case 'decrement': return {count: state.count - 1}; default: - // A reducer must always return a valid state. - // Alternatively you can throw an error if an invalid action is dispatched. - return state; + throw new Error(); } } function Counter({initialCount}) { - const [state, dispatch] = useReducer(reducer, {count: initialCount}); + const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} @@ -213,7 +213,7 @@ function Counter({initialCount}) { #### Specifying the initial state -There’s a few different ways to initialize `useReducer` state. You may choose either one depending on the use case. The simplest way to pass the initial state as a second argument: +There’s two different ways to initialize `useReducer` state. You may choose either one depending on the use case. The simplest way to pass the initial state as a second argument: ```js{3} const [state, dispatch] = useReducer( @@ -224,25 +224,13 @@ There’s a few different ways to initialize `useReducer` state. You may choose >Note > ->React doesn’t use the `state = initialState` argument convention popularized by Redux. The initial value sometimes needs to depend on props and so is specified from the Hook call instead. If you feel strongly about this, you can write `state = initialState` both in the reducer and inside the `useReducer` destructuring assignment, but it's not encouraged. +>React doesn’t use the `state = initialState` argument convention popularized by Redux. The initial value sometimes needs to depend on props and so is specified from the Hook call instead. If you feel strongly about this, you can call `useReducer(reducer, undefined, reducer)` to emulate the Redux behavior, but it's not encouraged. #### Lazy initialization -If calculating the initial state is expensive, you can initialize it lazily. In that case, you can skip the second argument (and pass `undefined`). The third `useReducer` argument is an optional `init` function that you can provide to calculate the initial value once: - -```js{3-4} - const [state, dispatch] = useReducer( - reducer, - undefined, - () => ({count: initialCount}) - ); -``` - -#### Lazy initialization with a transform - -For the most flexibility, you can specify *both* the second `initialArg` and the third `init` function arguments. In that case, the initial state will be set to `init(initialArg)`. +You can also create the initial state lazily. To do this, you can pass an `init` function as the third argument. The initial state will be set to `init(initialArg)`. -This is handy if you want to extract the lazy initialization logic outside your reducer: +It lets you extract the logic for calculating the initial state outside the reducer. This is also handy for resetting the state later in response to an action: ```js{1-3,11-12,21,26} function init(initialCount) { From 601c016f49719819dd74799f0b334e50311c8d88 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Tue, 5 Feb 2019 18:05:36 +0000 Subject: [PATCH 21/26] testing --- content/blog/2019-02-04-react-v16.8.0.md | 49 ++++++ content/docs/addons-test-utils.md | 194 ++++++++++++++++------- content/docs/hooks-faq.md | 62 ++++++++ 3 files changed, 246 insertions(+), 59 deletions(-) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-04-react-v16.8.0.md index f518ddde..f99297f6 100644 --- a/content/blog/2019-02-04-react-v16.8.0.md +++ b/content/blog/2019-02-04-react-v16.8.0.md @@ -48,6 +48,55 @@ Note that React Hooks don't cover *all* use cases for classes yet but they're [v Even while Hooks were in alpha, the React community created many interesting [examples](https://codesandbox.io/react-hooks) and [recipes](https://usehooks.com) using Hooks for animations, forms, subscriptions, integrating with other libraries, and so on. We're excited about Hooks because they make code reuse easier, helping you write your components in a simpler way and make great user experiences. We can't wait to see what you'll create next! +## Testing Hooks + +We have added a new API called `ReactTestUtils.act()` in this release. It ensures that the behavior in your tests matches what happens in the browser more closely. We recommend to wrap any code rendering and triggering updates to your components into `act()` calls. Testing libraries like [`react-testing-library`](https://github.com/kentcdodds/react-testing-library) can also wrap their APIs with it. + +For example, the counter example from [this page](/docs/hooks-effect.html) can be tested like this: + +```js{3,20-22,29-31} +import React from 'react'; +import ReactDOM from 'react-dom'; +import { act } from 'react-dom/test-utils'; +import Counter from './Counter'; + +let container; + +beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); +}); + +afterEach(() => { + document.body.removeChild(container); + container = null; +}); + +it('can render and update a counter', () => { + // Test first render and componentDidMount + act(() => { + ReactDOM.render(, container); + }); + const button = container.querySelector('button'); + const label = container.querySelector('p'); + expect(label.textContent).toBe('You clicked 0 times'); + expect(document.title).toBe('You clicked 0 times'); + + // Test second render and componentDidUpdate + act(() => { + button.dispatchEvent(new MouseEvent('click', {bubbles: true})); + }); + expect(label.textContent).toBe('You clicked 1 times'); + expect(document.title).toBe('You clicked 1 times'); +}); +``` + +The calls to `act()` will also flush the effects inside of them. + +If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it. Then you can test the component you wrote. + +To reduce the boilerplate, we recommend using [`react-testing-library`](https://git.io/react-testing-library) which is designed to encourage writing tests that use your components as the end users do. + ## Thanks We'd like to thank everybody who commented on the [Hooks RFC](https://github.com/reactjs/rfcs/pull/68) for sharing their feedback. We've read all of your comments and made some adjustments to the final API based on them. diff --git a/content/docs/addons-test-utils.md b/content/docs/addons-test-utils.md index c7ef5c02..40cec512 100644 --- a/content/docs/addons-test-utils.md +++ b/content/docs/addons-test-utils.md @@ -19,12 +19,11 @@ var ReactTestUtils = require('react-dom/test-utils'); // ES5 with npm > Note: > -> Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components' output. If you're deciding on a unit testing utility to use together with Jest, or any other test runner, it's worth checking out: [http://airbnb.io/enzyme/](http://airbnb.io/enzyme/) +> We recommend using [`react-testing-library`](https://git.io/react-testing-library) which is designed to enable and encourage writing tests that use your components as the end users do. > -> Alternatively, there is another testing utility called react-testing-library designed to enable and encourage writing tests that use your components as the end users use them. It also works with any test runner: [https://git.io/react-testing-library](https://git.io/react-testing-library) +> Alternatively, Airbnb has released a testing utility called [Enzyme](http://airbnb.io/enzyme/), which makes it easy to assert, manipulate, and traverse your React Components' output. - - [`Simulate`](#simulate) - - [`renderIntoDocument()`](#renderintodocument) + - [`act()`](#act) - [`mockComponent()`](#mockcomponent) - [`isElement()`](#iselement) - [`isElementOfType()`](#iselementoftype) @@ -38,68 +37,88 @@ var ReactTestUtils = require('react-dom/test-utils'); // ES5 with npm - [`findRenderedDOMComponentWithTag()`](#findrendereddomcomponentwithtag) - [`scryRenderedComponentsWithType()`](#scryrenderedcomponentswithtype) - [`findRenderedComponentWithType()`](#findrenderedcomponentwithtype) + - [`renderIntoDocument()`](#renderintodocument) + - [`Simulate`](#simulate) ## Reference -## Shallow Rendering - -When writing unit tests for React, shallow rendering can be helpful. Shallow rendering lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM. - -> Note: -> -> The shallow renderer has moved to `react-test-renderer/shallow`.
-> [Learn more about shallow rendering on its reference page.](/docs/shallow-renderer.html) - -## Other Utilities - -### `Simulate` - -```javascript -Simulate.{eventName}( - element, - [eventData] -) +### `act()` + +To prepare a component for assertions, wrap the code rendering it and performing updates inside an `act()` call. This makes your test run closer to how React works in the browser. + +For example, let's say we have this `Counter` component: + +```js +class App extends React.Component { + constructor(props) { + super(props); + this.state = {count: 0}; + this.handleClick = this.handleClick.bind(this); + } + componentDidMount() { + document.title = `You clicked ${this.state.count} times`; + } + componentDidUpdate() { + document.title = `You clicked ${this.state.count} times`; + } + handleClick() { + this.setState(state => ({ + count: state.count + 1, + })); + } + render() { + return ( +
+

You clicked {this.state.count} times

+ +
+ ); + } +} ``` -Simulate an event dispatch on a DOM node with optional `eventData` event data. - -`Simulate` has a method for [every event that React understands](/docs/events.html#supported-events). - -**Clicking an element** - -```javascript -// -const node = this.button; -ReactTestUtils.Simulate.click(node); +Here is how we can test it: + +```js{3,20-22,29-31} +import React from 'react'; +import ReactDOM from 'react-dom'; +import { act } from 'react-dom/test-utils'; +import Counter from './Counter'; + +let container; + +beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); +}); + +afterEach(() => { + document.body.removeChild(container); + container = null; +}); + +it('can render and update a counter', () => { + // Test first render and componentDidMount + act(() => { + ReactDOM.render(, container); + }); + const button = container.querySelector('button'); + const label = container.querySelector('p'); + expect(label.textContent).toBe('You clicked 0 times'); + expect(document.title).toBe('You clicked 0 times'); + + // Test second render and componentDidUpdate + act(() => { + button.dispatchEvent(new MouseEvent('click', {bubbles: true})); + }); + expect(label.textContent).toBe('You clicked 1 times'); + expect(document.title).toBe('You clicked 1 times'); +}); ``` -**Changing the value of an input field and then pressing ENTER.** - -```javascript -// this.textInput = node} /> -const node = this.textInput; -node.value = 'giraffe'; -ReactTestUtils.Simulate.change(node); -ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); -``` - -> Note -> -> You will have to provide any event property that you're using in your component (e.g. keyCode, which, etc...) as React is not creating any of these for you. - -* * * - -### `renderIntoDocument()` - -```javascript -renderIntoDocument(element) -``` - -Render a React element into a detached DOM node in the document. **This function requires a DOM.** - -> Note: -> -> You will need to have `window`, `window.document` and `window.document.createElement` globally available **before** you import `React`. Otherwise React will think it can't access the DOM and methods like `setState` won't work. +Don't forget that dispatching DOM events only works when the DOM container is added to the `document`. You can use a helper like [`react-testing-library`](https://github.com/kentcdodds/react-testing-library) to reduce the boilerplate code. * * * @@ -265,5 +284,62 @@ findRenderedComponentWithType( Same as [`scryRenderedComponentsWithType()`](#scryrenderedcomponentswithtype) but expects there to be one result and returns that one result, or throws exception if there is any other number of matches besides one. +*** + +### `renderIntoDocument()` + +```javascript +renderIntoDocument(element) +``` + +Render a React element into a detached DOM node in the document. **This function requires a DOM.** It is effectively equivalent to: + +```js +const domContainer = document.createElement('div'); +ReactDOM.render(element, domContainer); +``` + +> Note: +> +> You will need to have `window`, `window.document` and `window.document.createElement` globally available **before** you import `React`. Otherwise React will think it can't access the DOM and methods like `setState` won't work. + * * * +## Other Utilities + +### `Simulate` + +```javascript +Simulate.{eventName}( + element, + [eventData] +) +``` + +Simulate an event dispatch on a DOM node with optional `eventData` event data. + +`Simulate` has a method for [every event that React understands](/docs/events.html#supported-events). + +**Clicking an element** + +```javascript +// +const node = this.button; +ReactTestUtils.Simulate.click(node); +``` + +**Changing the value of an input field and then pressing ENTER.** + +```javascript +// this.textInput = node} /> +const node = this.textInput; +node.value = 'giraffe'; +ReactTestUtils.Simulate.change(node); +ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13}); +``` + +> Note +> +> You will have to provide any event property that you're using in your component (e.g. keyCode, which, etc...) as React is not creating any of these for you. + +* * * \ No newline at end of file diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 91c69529..068180bd 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -113,8 +113,70 @@ Importantly, custom Hooks give you the power to constrain React API if you'd lik From React's point of view, a component using Hooks is just a regular component. If your testing solution doesn't rely on React internals, testing components with Hooks shouldn't be different from how you normally test components. +For example, let's say we have this counter component: + +```js +function Example() { + const [count, setCount] = useState(0); + useEffect(() => { + document.title = `You clicked ${count} times`; + }); + return ( +
+

You clicked {count} times

+ +
+ ); +} +``` + +We'll test it using React DOM. To make sure that the behavior matches what happens in the browser, we'll wrap the code rendering and updating it into [`ReactTestUtils.act()`](/docs/test-utils.html#act) calls: + +```js{3,20-22,29-31} +import React from 'react'; +import ReactDOM from 'react-dom'; +import { act } from 'react-dom/test-utils'; +import Counter from './Counter'; + +let container; + +beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); +}); + +afterEach(() => { + document.body.removeChild(container); + container = null; +}); + +it('can render and update a counter', () => { + // Test first render and componentDidMount + act(() => { + ReactDOM.render(, container); + }); + const button = container.querySelector('button'); + const label = container.querySelector('p'); + expect(label.textContent).toBe('You clicked 0 times'); + expect(document.title).toBe('You clicked 0 times'); + + // Test second render and componentDidUpdate + act(() => { + button.dispatchEvent(new MouseEvent('click', {bubbles: true})); + }); + expect(label.textContent).toBe('You clicked 1 times'); + expect(document.title).toBe('You clicked 1 times'); +}); +``` + +The calls to `act()` will also flush the effects inside of them. + If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it. Then you can test the component you wrote. +To reduce the boilerplate, we recommend using [`react-testing-library`](https://git.io/react-testing-library) which is designed to encourage writing tests that use your components as the end users do. + ### What exactly do the [lint rules](https://www.npmjs.com/package/eslint-plugin-react-hooks) enforce? We provide an [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) that enforces [rules of Hooks](/docs/hooks-rules.html) to avoid bugs. It assumes that any function starting with "`use`" and a capital letter right after it is a Hook. We recognize this heuristic isn't perfect and there may be some false positives, but without an ecosystem-wide convention there is just no way to make Hooks work well -- and longer names will discourage people from either adopting Hooks or following the convention. From 30914131e8af651bf464a9380e47d7795b8827b9 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 5 Feb 2019 18:21:24 +0000 Subject: [PATCH 22/26] Renamed Hooks blog/date --- .../{2019-02-04-react-v16.8.0.md => 2019-02-05-react-v16.8.0.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename content/blog/{2019-02-04-react-v16.8.0.md => 2019-02-05-react-v16.8.0.md} (100%) diff --git a/content/blog/2019-02-04-react-v16.8.0.md b/content/blog/2019-02-05-react-v16.8.0.md similarity index 100% rename from content/blog/2019-02-04-react-v16.8.0.md rename to content/blog/2019-02-05-react-v16.8.0.md From ee909e5a675babde98711197699402befc043ff4 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 5 Feb 2019 18:28:01 +0000 Subject: [PATCH 23/26] Udpated changelog --- content/blog/2019-02-05-react-v16.8.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/2019-02-05-react-v16.8.0.md b/content/blog/2019-02-05-react-v16.8.0.md index f99297f6..1ce3c3fe 100644 --- a/content/blog/2019-02-05-react-v16.8.0.md +++ b/content/blog/2019-02-05-react-v16.8.0.md @@ -176,7 +176,7 @@ Then add it to your ESLint configuration: * Support synchronous thenables passed to `React.lazy()`. ([@gaearon](https://github.com/gaearon) in [#14626](https://github.com/facebook/react/pull/14626)) * Render components with Hooks twice in Strict Mode (DEV-only) to match class behavior. ([@gaearon](https://github.com/gaearon) in [#14654](https://github.com/facebook/react/pull/14654)) * Warn about mismatching Hook order in development. ([@threepointone](https://github.com/threepointone) in [#14585](https://github.com/facebook/react/pull/14585) and [@acdlite](https://github.com/acdlite) in [#14591](https://github.com/facebook/react/pull/14591)) - +* Effect clean-up functions must return either `undefined` or a function. All other values, including `null`, are not allowed. [@acdlite](https://github.com/acdlite) in [#14119](https://github.com/facebook/react/pull/14119) ### React Test Renderer From a0db3e7f1753a33b64e6d9ea52ed9d1b1b8f2887 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 5 Feb 2019 18:39:25 +0000 Subject: [PATCH 24/26] Replaced inaccurate comments --- content/blog/2019-02-05-react-v16.8.0.md | 4 ++-- content/docs/hooks-faq.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/blog/2019-02-05-react-v16.8.0.md b/content/blog/2019-02-05-react-v16.8.0.md index 1ce3c3fe..16eac65d 100644 --- a/content/blog/2019-02-05-react-v16.8.0.md +++ b/content/blog/2019-02-05-react-v16.8.0.md @@ -73,7 +73,7 @@ afterEach(() => { }); it('can render and update a counter', () => { - // Test first render and componentDidMount + // Test first render and effect act(() => { ReactDOM.render(, container); }); @@ -82,7 +82,7 @@ it('can render and update a counter', () => { expect(label.textContent).toBe('You clicked 0 times'); expect(document.title).toBe('You clicked 0 times'); - // Test second render and componentDidUpdate + // Test second render and effect act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 068180bd..30c5e681 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -153,7 +153,7 @@ afterEach(() => { }); it('can render and update a counter', () => { - // Test first render and componentDidMount + // Test first render and effect act(() => { ReactDOM.render(, container); }); @@ -162,7 +162,7 @@ it('can render and update a counter', () => { expect(label.textContent).toBe('You clicked 0 times'); expect(document.title).toBe('You clicked 0 times'); - // Test second render and componentDidUpdate + // Test second render and effect act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); From 8cae0666577b3ce157a948f024017a51c71c5817 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 5 Feb 2019 18:41:23 +0000 Subject: [PATCH 25/26] Added ReactTestUtils.act() to CHANGELOG --- content/blog/2019-02-05-react-v16.8.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/blog/2019-02-05-react-v16.8.0.md b/content/blog/2019-02-05-react-v16.8.0.md index 16eac65d..d3a7ac69 100644 --- a/content/blog/2019-02-05-react-v16.8.0.md +++ b/content/blog/2019-02-05-react-v16.8.0.md @@ -182,6 +182,7 @@ Then add it to your ESLint configuration: * Support Hooks in the shallow renderer. ([@trueadm](https://github.com/trueadm) in [#14567](https://github.com/facebook/react/pull/14567)) * Fix wrong state in `shouldComponentUpdate` in the presence of `getDerivedStateFromProps` for Shallow Renderer. ([@chenesan](https://github.com/chenesan) in [#14613](https://github.com/facebook/react/pull/14613)) +* Add `ReactTestUtils.act()` for batching updates so that tests more closely match real behavior. ([@threepointone](https://github.com/threepointone) in [#14744](https://github.com/facebook/react/pull/14744)) ### ESLint Plugin: React Hooks From 8fa112eeba9f9ecb12189ab8520d446537e4e25f Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 6 Feb 2019 08:03:03 +0000 Subject: [PATCH 26/26] Moved blog post to Feb 6th --- .../{2019-02-05-react-v16.8.0.md => 2019-02-06-react-v16.8.0.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename content/blog/{2019-02-05-react-v16.8.0.md => 2019-02-06-react-v16.8.0.md} (100%) diff --git a/content/blog/2019-02-05-react-v16.8.0.md b/content/blog/2019-02-06-react-v16.8.0.md similarity index 100% rename from content/blog/2019-02-05-react-v16.8.0.md rename to content/blog/2019-02-06-react-v16.8.0.md