From 444896ef8fa9e5155ef34216500ffe4f3c177ab5 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 5 Feb 2018 08:28:41 -0800 Subject: [PATCH 001/107] Initial draft for 16.3 release blog --- content/blog/2018-02-07-react-v-16-3.md | 49 +++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 content/blog/2018-02-07-react-v-16-3.md diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md new file mode 100644 index 00000000..cef4795a --- /dev/null +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -0,0 +1,49 @@ +--- +title: "React v16.3.0: New lifecycles and context" +author: [bvaughn] +--- + +This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, and an official context API! + +For the past few months, the React team has been working on support for asynchronous rendering. We are excited about the new features this will enable, and we've learned that some changes will be required to the way we write React components. + +We're releasing version 16.3 primarily so that open source maintainers can start incorporating these changes into their libraries well in advance of the next major release. **However, you should not feel pressured to make changes to your application code yet.** We respect semver and will not ship breaking changes in a minor version! + +Read on to learn more about the release! + +## Component Lifecycle Changes + +React's class component API has been around for years with little change. However, as we add support for more advanced features (such as [error boundaries](/docs/react-component.html#componentdidcatch) and the upcoming async rendering mode) we stretch this model in ways that it was not originally intended. + +For example, with the current API, it is too easy to block the initial render with non-essential logic. In part this is because there are too many ways to accomplish a given task, and it can be unclear which is best. We've observed that the interrupting behavior of error handling is often not taken into consideration and can result in memory leaks- (something that will also impact the upcoming async rendering mode). The current class component API also complicates other efforts, like our work on a React compiler. + +Many of these issues are exacerbated by a subset of the component lifecycles (`componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate`). For this reason, we have decided to deprecate those methods. + +> **Note:** +> +> Deprecation warnings will be enabled in version 16.4, **but the deprecated lifecycles will continue to work until version 17**. After version 17, only the new "UNSAFE_" lifecycles will work. + +We are also adding a new static lifecycle, `getDerivedStateFromProps`, to replace the deprecated `componentWillReceiveProps`. + +[Learn more about these lifecycle changes here.](#) + +## `StrictMode` Component + +`StrictMode` is a tool for highlighting potential problems in an application. Like `Fragment`, `StrictMode` does not render any visible UI. It simply activates additional checks and warnings for its descendants. + + +> **Note:** +> +> `StrictMode` checks are run in development mode only; they do not impact the production build. + +Although it is not possible for strict mode to catch all problems (eg mutation), it can help with many. If you see warnings in strict mode, those things will likely cause bugs for async rendering. + +In version 16.3, `StrictMode` helps with two things: identifying unsafe lifecycles and detecting unexpected side effects. Additional functionality will be added with future releases of React. + +[Learn more about the `StrictMode` component here.](#) + +## Official Context API + +For many years, React has offered an experimental API for context. Although it was a powerful tool, our advice was mostly to [avoid using it](/docs/context.html#why-not-to-use-context) because of potential problems with the API. We've always intended to replace the experimental API with a better one, and as of version 16.3- we've finally done that! + +[Learn more about the new context API here.](#) From 141de6606360c114ada2df356210ba28f5503a6a Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 5 Feb 2018 10:26:08 -0800 Subject: [PATCH 002/107] Wording changes in response to PR feedback --- content/blog/2018-02-07-react-v-16-3.md | 32 ++++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index cef4795a..39070c2b 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -5,25 +5,35 @@ author: [bvaughn] This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, and an official context API! -For the past few months, the React team has been working on support for asynchronous rendering. We are excited about the new features this will enable, and we've learned that some changes will be required to the way we write React components. +For the past few months, the React team has been working on support for [asynchronous rendering](#). We are excited about the new features this will enable, and we've learned that some changes will be required to the way we write React components. We're releasing version 16.3 primarily so that open source maintainers can start incorporating these changes into their libraries well in advance of the next major release. **However, you should not feel pressured to make changes to your application code yet.** We respect semver and will not ship breaking changes in a minor version! -Read on to learn more about the release! +Read on to learn more about the release. + +## Official Context API + +For many years, React has offered an experimental API for context. Although it was a powerful tool, our advice was mostly to [avoid using it](/docs/context.html#why-not-to-use-context) because of potential problems with the API. We've always intended to replace the experimental API with a better one, and as of version 16.3- we've finally done that! + +[Learn more about the new context API here.](#) ## Component Lifecycle Changes -React's class component API has been around for years with little change. However, as we add support for more advanced features (such as [error boundaries](/docs/react-component.html#componentdidcatch) and the upcoming async rendering mode) we stretch this model in ways that it was not originally intended. +React's class component API has been around for years with little change. However, as we add support for more advanced features (such as [error boundaries](/docs/react-component.html#componentdidcatch) and the upcoming [async rendering mode](#)) we stretch this model in ways that it was not originally intended. + +For example, with the current API, it is too easy to block the initial render with non-essential logic. In part this is because there are too many ways to accomplish a given task, and it can be unclear which is best. We've observed that the interrupting behavior of error handling is often not taken into consideration and can result in memory leaks—(something that will also impact the upcoming async rendering mode). The current class component API also complicates other efforts, like our work on a React compiler. -For example, with the current API, it is too easy to block the initial render with non-essential logic. In part this is because there are too many ways to accomplish a given task, and it can be unclear which is best. We've observed that the interrupting behavior of error handling is often not taken into consideration and can result in memory leaks- (something that will also impact the upcoming async rendering mode). The current class component API also complicates other efforts, like our work on a React compiler. +Many of these issues are exacerbated by a subset of the component lifecycles (`componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate`). These also happen to be the lifecycles that cause the most confusion within the React community. For these reasons, we are going to deprecate those methods in favor of better alternatives. -Many of these issues are exacerbated by a subset of the component lifecycles (`componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate`). For this reason, we have decided to deprecate those methods. +We recognize that this change will impact many existing components. (At Facebook, we maintain more than 50,000 React components, and we can't tell our engineers to rewrite them either.) Because of this, the migration path will be as gradual as possible, and will provide escape hatches. > **Note:** > -> Deprecation warnings will be enabled in version 16.4, **but the deprecated lifecycles will continue to work until version 17**. After version 17, only the new "UNSAFE_" lifecycles will work. +> Deprecation warnings will be enabled in version 16.4, **but the deprecated lifecycles will continue to work until version 17**. +> +> After version 17, it will still be possible to use them, but they will be aliased with an "UNSAFE_" prefix to indicate that they might cause issues. We have also prepared an [automated script to rename them](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) in existing code. -We are also adding a new static lifecycle, `getDerivedStateFromProps`, to replace the deprecated `componentWillReceiveProps`. +We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safer alternative to the deprecated `componentWillReceiveProps`. [Learn more about these lifecycle changes here.](#) @@ -36,14 +46,8 @@ We are also adding a new static lifecycle, `getDerivedStateFromProps`, to replac > > `StrictMode` checks are run in development mode only; they do not impact the production build. -Although it is not possible for strict mode to catch all problems (eg mutation), it can help with many. If you see warnings in strict mode, those things will likely cause bugs for async rendering. +Although it is not possible for strict mode to catch all problems (e.g. certain types of mutation), it can help with many. If you see warnings in strict mode, those things will likely cause bugs for async rendering. In version 16.3, `StrictMode` helps with two things: identifying unsafe lifecycles and detecting unexpected side effects. Additional functionality will be added with future releases of React. [Learn more about the `StrictMode` component here.](#) - -## Official Context API - -For many years, React has offered an experimental API for context. Although it was a powerful tool, our advice was mostly to [avoid using it](/docs/context.html#why-not-to-use-context) because of potential problems with the API. We've always intended to replace the experimental API with a better one, and as of version 16.3- we've finally done that! - -[Learn more about the new context API here.](#) From ce57928a0c397aac3b05289c0c9be9cf3b123890 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 6 Feb 2018 10:47:10 -0800 Subject: [PATCH 003/107] Added entry for createRef API --- content/blog/2018-02-07-react-v-16-3.md | 11 ++++++++++- examples/16-3-release-blog-create-ref.js | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 examples/16-3-release-blog-create-ref.js diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index 39070c2b..b80838c3 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -3,7 +3,7 @@ title: "React v16.3.0: New lifecycles and context" author: [bvaughn] --- -This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, and an official context API! +This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, an official context API, and a better way for managing refs! For the past few months, the React team has been working on support for [asynchronous rendering](#). We are excited about the new features this will enable, and we've learned that some changes will be required to the way we write React components. @@ -17,6 +17,15 @@ For many years, React has offered an experimental API for context. Although it w [Learn more about the new context API here.](#) +## `createRef` API + +Previously, React provided two ways for managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had [several downsides](https://github.com/facebook/react/issues/1373) and so our official recomendation was to [use the callback form instead](https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs). + +Version 16.3 adds a new option for managing refs that offers the convenience of a string ref without any of the downsides: +`embed:16-3-release-blog-create-ref.js` + +[Learn more about the new `createRef` API here.](#) + ## Component Lifecycle Changes React's class component API has been around for years with little change. However, as we add support for more advanced features (such as [error boundaries](/docs/react-component.html#componentdidcatch) and the upcoming [async rendering mode](#)) we stretch this model in ways that it was not originally intended. diff --git a/examples/16-3-release-blog-create-ref.js b/examples/16-3-release-blog-create-ref.js new file mode 100644 index 00000000..9f613f22 --- /dev/null +++ b/examples/16-3-release-blog-create-ref.js @@ -0,0 +1,19 @@ +class MyComponent extends React.Component { + // highlight-next-line + _divRef = React.createRef(); + + render() { + // highlight-range{4} + return ( + + ); + } + + componentDidMount() { + // highlight-next-line + this._divRef.value.focus(); + } +} From da29d893e49ab33bfda84036754c9128401cbf97 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 6 Feb 2018 10:48:38 -0800 Subject: [PATCH 004/107] Added note about string ref API to strict mode section --- content/blog/2018-02-07-react-v-16-3.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index b80838c3..6f526b62 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -57,6 +57,11 @@ We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safe Although it is not possible for strict mode to catch all problems (e.g. certain types of mutation), it can help with many. If you see warnings in strict mode, those things will likely cause bugs for async rendering. -In version 16.3, `StrictMode` helps with two things: identifying unsafe lifecycles and detecting unexpected side effects. Additional functionality will be added with future releases of React. +In version 16.3, `StrictMode` helps with only a handful of things: +* Identifying components with unsafe lifecycles +* Identifying usage of the legacy string ref API +* Detecting unexpected side effects + +Additional functionality will be added with future releases of React. [Learn more about the `StrictMode` component here.](#) From a55480bc8e04cd8ef6b704499ef31a20c3618443 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 6 Feb 2018 10:53:28 -0800 Subject: [PATCH 005/107] Small wording nit --- content/blog/2018-02-07-react-v-16-3.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index 6f526b62..a1439f40 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -57,9 +57,9 @@ We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safe Although it is not possible for strict mode to catch all problems (e.g. certain types of mutation), it can help with many. If you see warnings in strict mode, those things will likely cause bugs for async rendering. -In version 16.3, `StrictMode` helps with only a handful of things: +In version 16.3, `StrictMode` helps with: * Identifying components with unsafe lifecycles -* Identifying usage of the legacy string ref API +* Warning about legacy string ref API usage * Detecting unexpected side effects Additional functionality will be added with future releases of React. From 935d2a104b9ba6ef74721d133afffec2c38c4064 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 6 Feb 2018 11:08:37 -0800 Subject: [PATCH 006/107] Minor edits in response to PR feedback --- content/blog/2018-02-07-react-v-16-3.md | 9 +++++++-- examples/16-3-release-blog-create-ref.js | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index a1439f40..98d33574 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -3,7 +3,7 @@ title: "React v16.3.0: New lifecycles and context" author: [bvaughn] --- -This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, an official context API, and a better way for managing refs! +This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, an official context API, and a new ergonomic ref API! For the past few months, the React team has been working on support for [asynchronous rendering](#). We are excited about the new features this will enable, and we've learned that some changes will be required to the way we write React components. @@ -24,6 +24,12 @@ Previously, React provided two ways for managing refs: the legacy string ref API Version 16.3 adds a new option for managing refs that offers the convenience of a string ref without any of the downsides: `embed:16-3-release-blog-create-ref.js` +> **Note:** +> +> Callback refs will continue to be supported in addition to the new `createRef` API. +> +> You don't need to replace callback refs in your components. They are slightly more flexible, so they will remain as an advanced feature. + [Learn more about the new `createRef` API here.](#) ## Component Lifecycle Changes @@ -50,7 +56,6 @@ We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safe `StrictMode` is a tool for highlighting potential problems in an application. Like `Fragment`, `StrictMode` does not render any visible UI. It simply activates additional checks and warnings for its descendants. - > **Note:** > > `StrictMode` checks are run in development mode only; they do not impact the production build. diff --git a/examples/16-3-release-blog-create-ref.js b/examples/16-3-release-blog-create-ref.js index 9f613f22..f189e0d0 100644 --- a/examples/16-3-release-blog-create-ref.js +++ b/examples/16-3-release-blog-create-ref.js @@ -1,19 +1,19 @@ class MyComponent extends React.Component { // highlight-next-line - _divRef = React.createRef(); + divRef = React.createRef(); render() { // highlight-range{4} return ( ); } componentDidMount() { // highlight-next-line - this._divRef.value.focus(); + this.divRef.value.focus(); } } From ab62e88e277d88a70f607117954855eb737e5b6e Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 7 Feb 2018 09:25:36 -0800 Subject: [PATCH 007/107] Formatted example --- examples/16-3-release-blog-create-ref.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/16-3-release-blog-create-ref.js b/examples/16-3-release-blog-create-ref.js index f189e0d0..77cbb40a 100644 --- a/examples/16-3-release-blog-create-ref.js +++ b/examples/16-3-release-blog-create-ref.js @@ -3,13 +3,8 @@ class MyComponent extends React.Component { divRef = React.createRef(); render() { - // highlight-range{4} - return ( - - ); + // highlight-next-line + return ; } componentDidMount() { From 08d444eadad1c70c074734f32b1a0dbbf1d39171 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 12 Feb 2018 10:08:08 -0800 Subject: [PATCH 008/107] Wordsmithing in response to PR feedback --- content/blog/2018-02-07-react-v-16-3.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index 98d33574..91947c6a 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -13,7 +13,11 @@ Read on to learn more about the release. ## Official Context API -For many years, React has offered an experimental API for context. Although it was a powerful tool, our advice was mostly to [avoid using it](/docs/context.html#why-not-to-use-context) because of potential problems with the API. We've always intended to replace the experimental API with a better one, and as of version 16.3- we've finally done that! +For many years, React has offered an experimental API for context. Although it was a powerful tool, our advice was mostly to [avoid using it](/docs/context.html#why-not-to-use-context) because of potential problems with the API. We've always intended to replace the experimental API with a better one, and as of version 16.3 the new API is available! + +> **Note** +> +> The old context API will keep working for all React 16 minor releases, so you will have time to migrate. [Learn more about the new context API here.](#) @@ -44,11 +48,11 @@ We recognize that this change will impact many existing components. (At Facebook > **Note:** > -> Deprecation warnings will be enabled in version 16.4, **but the deprecated lifecycles will continue to work until version 17**. +> Deprecation warnings will be enabled in version 16.4, **but the legacy lifecycles will continue to work until version 17**. > > After version 17, it will still be possible to use them, but they will be aliased with an "UNSAFE_" prefix to indicate that they might cause issues. We have also prepared an [automated script to rename them](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) in existing code. -We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safer alternative to the deprecated `componentWillReceiveProps`. +We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safer alternative to the legacy `componentWillReceiveProps`. [Learn more about these lifecycle changes here.](#) From 5a1d653f7612a511470685e6b9209fae6b62ae8a Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 13 Feb 2018 11:15:09 -0800 Subject: [PATCH 009/107] Incorporated Sophie's PR feedback --- content/blog/2018-02-07-react-v-16-3.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index 91947c6a..9d8c4ad6 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -5,19 +5,21 @@ author: [bvaughn] This release includes a new class component lifecycle (`getDerivedStateFromProps`), a new `StrictMode` component, an official context API, and a new ergonomic ref API! -For the past few months, the React team has been working on support for [asynchronous rendering](#). We are excited about the new features this will enable, and we've learned that some changes will be required to the way we write React components. +For the past few months, the React team has been working on support for [asynchronous rendering](#). We are excited about the new features it will enable. -We're releasing version 16.3 primarily so that open source maintainers can start incorporating these changes into their libraries well in advance of the next major release. **However, you should not feel pressured to make changes to your application code yet.** We respect semver and will not ship breaking changes in a minor version! +We've also learned that some long-term changes will be required to the way we write React components. However, we respect semver and **will not ship breaking changes in a minor version**! Read on to learn more about the release. ## Official Context API -For many years, React has offered an experimental API for context. Although it was a powerful tool, our advice was mostly to [avoid using it](/docs/context.html#why-not-to-use-context) because of potential problems with the API. We've always intended to replace the experimental API with a better one, and as of version 16.3 the new API is available! +For many years, React has offered an experimental API for context. Although it was a powerful tool, [its use was discouraged](/docs/context.html#why-not-to-use-context) because of inherent problems in the API, and because we always intended to replace the experimental API with a better one. + +Version 16.3 introduces a new context API that is more efficient and supports both static type checking and deep updates. > **Note** > -> The old context API will keep working for all React 16 minor releases, so you will have time to migrate. +> The old context API will keep working for all React 16.x releases, so you will have time to migrate. [Learn more about the new context API here.](#) @@ -40,7 +42,7 @@ Version 16.3 adds a new option for managing refs that offers the convenience of React's class component API has been around for years with little change. However, as we add support for more advanced features (such as [error boundaries](/docs/react-component.html#componentdidcatch) and the upcoming [async rendering mode](#)) we stretch this model in ways that it was not originally intended. -For example, with the current API, it is too easy to block the initial render with non-essential logic. In part this is because there are too many ways to accomplish a given task, and it can be unclear which is best. We've observed that the interrupting behavior of error handling is often not taken into consideration and can result in memory leaks—(something that will also impact the upcoming async rendering mode). The current class component API also complicates other efforts, like our work on a React compiler. +For example, with the current API, it is too easy to block the initial render with non-essential logic. In part this is because there are too many ways to accomplish a given task, and it can be unclear which is best. We've observed that the interrupting behavior of error handling is often not taken into consideration and can result in memory leaks (something that will also impact the upcoming async rendering mode). The current class component API also complicates other efforts, like our work on [prototyping a React compiler](https://twitter.com/trueadm/status/944908776896978946). Many of these issues are exacerbated by a subset of the component lifecycles (`componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate`). These also happen to be the lifecycles that cause the most confusion within the React community. For these reasons, we are going to deprecate those methods in favor of better alternatives. @@ -50,7 +52,7 @@ We recognize that this change will impact many existing components. (At Facebook > > Deprecation warnings will be enabled in version 16.4, **but the legacy lifecycles will continue to work until version 17**. > -> After version 17, it will still be possible to use them, but they will be aliased with an "UNSAFE_" prefix to indicate that they might cause issues. We have also prepared an [automated script to rename them](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) in existing code. +> Even in version 17, it will still be possible to use them, but they will be aliased with an "UNSAFE_" prefix to indicate that they might cause issues. We have also prepared an [automated script to rename them](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) in existing code. We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safer alternative to the legacy `componentWillReceiveProps`. @@ -58,11 +60,11 @@ We are also adding a new static lifecycle, `getDerivedStateFromProps`, as a safe ## `StrictMode` Component -`StrictMode` is a tool for highlighting potential problems in an application. Like `Fragment`, `StrictMode` does not render any visible UI. It simply activates additional checks and warnings for its descendants. +`StrictMode` is a tool for highlighting potential problems in an application. Like `Fragment`, `StrictMode` does not render any visible UI. It activates additional checks and warnings for its descendants. > **Note:** > -> `StrictMode` checks are run in development mode only; they do not impact the production build. +> `StrictMode` checks are run in development mode only; _they do not impact the production build_. Although it is not possible for strict mode to catch all problems (e.g. certain types of mutation), it can help with many. If you see warnings in strict mode, those things will likely cause bugs for async rendering. @@ -73,4 +75,4 @@ In version 16.3, `StrictMode` helps with: Additional functionality will be added with future releases of React. -[Learn more about the `StrictMode` component here.](#) +[Learn more about the `StrictMode` component here.](/docs/strict-mode.html) From 8494428bcb3dd8d4778a58ebe25e7c1f908c7f53 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 13 Feb 2018 11:44:39 -0800 Subject: [PATCH 010/107] Added example of before/after context API --- content/blog/2018-02-07-react-v-16-3.md | 8 +++- .../context-example-after.js | 34 +++++++++++++++ .../context-example-before.js | 42 +++++++++++++++++++ .../create-ref-example.js} | 0 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 examples/16-3-release-blog-post/context-example-after.js create mode 100644 examples/16-3-release-blog-post/context-example-before.js rename examples/{16-3-release-blog-create-ref.js => 16-3-release-blog-post/create-ref-example.js} (100%) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index 9d8c4ad6..d5307c13 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -21,6 +21,12 @@ Version 16.3 introduces a new context API that is more efficient and supports bo > > The old context API will keep working for all React 16.x releases, so you will have time to migrate. +Here is an example of how you might inject a "theme" using the old context API: +`embed:16-3-release-blog-post/context-example-before.js` + +And here is an example of how you might do the same with the new context API: +`embed:16-3-release-blog-post/context-example-after.js` + [Learn more about the new context API here.](#) ## `createRef` API @@ -28,7 +34,7 @@ Version 16.3 introduces a new context API that is more efficient and supports bo Previously, React provided two ways for managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had [several downsides](https://github.com/facebook/react/issues/1373) and so our official recomendation was to [use the callback form instead](https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs). Version 16.3 adds a new option for managing refs that offers the convenience of a string ref without any of the downsides: -`embed:16-3-release-blog-create-ref.js` +`embed:16-3-release-blog-post/create-ref-example.js` > **Note:** > diff --git a/examples/16-3-release-blog-post/context-example-after.js b/examples/16-3-release-blog-post/context-example-after.js new file mode 100644 index 00000000..0f9137f4 --- /dev/null +++ b/examples/16-3-release-blog-post/context-example-after.js @@ -0,0 +1,34 @@ +// highlight-next-line +const ThemeContext = React.createContext('light'); + +class ThemeProvider extends React.Component { + state = {theme: 'light'}; + + render() { + // highlight-range{2} + return ( + + {this.props.children} + + ); + } +} + +class ThemedButton extends React.Component { + render() { + // highlight-range{2-4} + return ( + + {theme => { + const background = theme ? '#fff' : '#000'; + + return ( + + ); + }} + + ); + } +} diff --git a/examples/16-3-release-blog-post/context-example-before.js b/examples/16-3-release-blog-post/context-example-before.js new file mode 100644 index 00000000..fac8e39f --- /dev/null +++ b/examples/16-3-release-blog-post/context-example-before.js @@ -0,0 +1,42 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +class ThemeProvider extends React.Component { + // highlight-range{1-3} + static childContextTypes = { + theme: PropTypes.string, + }; + + state = { + theme: 'light', + }; + + // highlight-range{1-5} + getChildContext() { + return { + theme: state.theme, + }; + } + + render() { + return this.props.children; + } +} + +class ThemedButton extends React.Component { + // highlight-range{1-3} + static contextTypes = { + theme: PropTypes.string, + }; + + render() { + // highlight-next-line + const background = this.context.theme ? '#fff' : '#000'; + + return ( + + ); + } +} diff --git a/examples/16-3-release-blog-create-ref.js b/examples/16-3-release-blog-post/create-ref-example.js similarity index 100% rename from examples/16-3-release-blog-create-ref.js rename to examples/16-3-release-blog-post/create-ref-example.js From c08533af9fcf6a0dee3b99844d92987f857d46c3 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 13 Feb 2018 12:40:31 -0800 Subject: [PATCH 011/107] Removed context-before example --- content/blog/2018-02-07-react-v-16-3.md | 7 +--- .../context-example-before.js | 42 ------------------- ...xt-example-after.js => context-example.js} | 12 +----- 3 files changed, 4 insertions(+), 57 deletions(-) delete mode 100644 examples/16-3-release-blog-post/context-example-before.js rename examples/16-3-release-blog-post/{context-example-after.js => context-example.js} (66%) diff --git a/content/blog/2018-02-07-react-v-16-3.md b/content/blog/2018-02-07-react-v-16-3.md index d5307c13..f16fd4cd 100644 --- a/content/blog/2018-02-07-react-v-16-3.md +++ b/content/blog/2018-02-07-react-v-16-3.md @@ -21,11 +21,8 @@ Version 16.3 introduces a new context API that is more efficient and supports bo > > The old context API will keep working for all React 16.x releases, so you will have time to migrate. -Here is an example of how you might inject a "theme" using the old context API: -`embed:16-3-release-blog-post/context-example-before.js` - -And here is an example of how you might do the same with the new context API: -`embed:16-3-release-blog-post/context-example-after.js` +Here is an example of how you might inject a "theme" using the new context API: +`embed:16-3-release-blog-post/context-example.js` [Learn more about the new context API here.](#) diff --git a/examples/16-3-release-blog-post/context-example-before.js b/examples/16-3-release-blog-post/context-example-before.js deleted file mode 100644 index fac8e39f..00000000 --- a/examples/16-3-release-blog-post/context-example-before.js +++ /dev/null @@ -1,42 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; - -class ThemeProvider extends React.Component { - // highlight-range{1-3} - static childContextTypes = { - theme: PropTypes.string, - }; - - state = { - theme: 'light', - }; - - // highlight-range{1-5} - getChildContext() { - return { - theme: state.theme, - }; - } - - render() { - return this.props.children; - } -} - -class ThemedButton extends React.Component { - // highlight-range{1-3} - static contextTypes = { - theme: PropTypes.string, - }; - - render() { - // highlight-next-line - const background = this.context.theme ? '#fff' : '#000'; - - return ( - - ); - } -} diff --git a/examples/16-3-release-blog-post/context-example-after.js b/examples/16-3-release-blog-post/context-example.js similarity index 66% rename from examples/16-3-release-blog-post/context-example-after.js rename to examples/16-3-release-blog-post/context-example.js index 0f9137f4..5d6b43bb 100644 --- a/examples/16-3-release-blog-post/context-example-after.js +++ b/examples/16-3-release-blog-post/context-example.js @@ -5,7 +5,7 @@ class ThemeProvider extends React.Component { state = {theme: 'light'}; render() { - // highlight-range{2} + // highlight-range{2-4} return ( {this.props.children} @@ -19,15 +19,7 @@ class ThemedButton extends React.Component { // highlight-range{2-4} return ( - {theme => { - const background = theme ? '#fff' : '#000'; - - return ( - - ); - }} + {theme => + ); + } +} + +// highlight-next-line +const FancyThemedButton = withTheme(FancyButton); + +// We can render FancyThemedButton as if it were a FancyButton +// It will automatically receive the current "theme", +// And the HOC will pass through our other props. +; diff --git a/examples/16-3-release-blog-post/forward-ref-example.js b/examples/16-3-release-blog-post/forward-ref-example.js new file mode 100644 index 00000000..3c6193e0 --- /dev/null +++ b/examples/16-3-release-blog-post/forward-ref-example.js @@ -0,0 +1,34 @@ +function withTheme(Component) { + // highlight-next-line + function ThemedComponent({forwardedRef, ...rest}) { + // highlight-range{6} + return ( + + {theme => ( + + )} + + ); + } + + // Intercept the "ref" and pass it as a custom prop. + // highlight-range{1-3} + return React.forwardRef((props, ref) => ( + + )); +} + +// highlight-next-line +const fancyButtonRef = React.createRef(); + +// fancyButtonRef will now point to FancyButton +// highlight-range{4} +; diff --git a/examples/16-3-release-blog-post/hoc-theme-example.js b/examples/16-3-release-blog-post/hoc-theme-example.js new file mode 100644 index 00000000..ba0138de --- /dev/null +++ b/examples/16-3-release-blog-post/hoc-theme-example.js @@ -0,0 +1,10 @@ +function withTheme(Component) { + return function ThemedComponent(props) { + // highlight-range{2-4} + return ( + + {theme => } + + ); + }; +} From a937c46e025ca804545f1099791696afe49fc2dd Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 15 Mar 2018 10:05:02 -0700 Subject: [PATCH 039/107] Typo fixes --- content/blog/2018-03-20-react-v-16-3.md | 4 ++-- content/docs/strict-mode.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/blog/2018-03-20-react-v-16-3.md b/content/blog/2018-03-20-react-v-16-3.md index e6ed3a45..3c71e7ed 100644 --- a/content/blog/2018-03-20-react-v-16-3.md +++ b/content/blog/2018-03-20-react-v-16-3.md @@ -7,7 +7,7 @@ This release includes a new class component lifecycle (`getDerivedStateFromProps For the past few months, the React team has been working on support for [asynchronous rendering](/blog/2018/03/01/sneak-peek-beyond-react-16.html). We are excited about the new features it will enable. -We've also learned that some long-term changes will be required to the way we write React components. However, we respect semver and **will not ship breaking changes in a minor version**! +We've also learned that some long-term changes will be required to the way we write React components. However, we respect [semver](https://semver.org/) and **will not ship breaking changes in a minor version**! Read on to learn more about the release. @@ -28,7 +28,7 @@ Here is an example illustrating how you might inject a "theme" using the new con ## `createRef` API -Previously, React provided two ways for managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had [several downsides](https://github.com/facebook/react/issues/1373) and so our official recomendation was to use the callback form instead. +Previously, React provided two ways of managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had [several downsides](https://github.com/facebook/react/issues/1373) and so our official recommendation was to use the callback form instead. Version 16.3 adds a new option for managing refs that offers the convenience of a string ref without any of the downsides: `embed:16-3-release-blog-post/create-ref-example.js` diff --git a/content/docs/strict-mode.md b/content/docs/strict-mode.md index ec89a8d1..14ab139a 100644 --- a/content/docs/strict-mode.md +++ b/content/docs/strict-mode.md @@ -34,7 +34,7 @@ Addressing the issues identified by strict mode _now_ will make it easier for yo ### Warning about legacy string ref API usage -Previously, React provided two ways for managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had [several downsides](https://github.com/facebook/react/issues/1373) and so our official recomendation was to [use the callback form instead](https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs). +Previously, React provided two ways for managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had [several downsides](https://github.com/facebook/react/issues/1373) and so our official recommendation was to [use the callback form instead](https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs). React 16.3 added a third option that offers the convenience of a string ref without any of the downsides: `embed:16-3-release-blog-post/create-ref-example.js` From 201fcadfa7fbd3ceb6bd0b04c6f09e76bf33a5bf Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 16 Mar 2018 09:30:07 -0700 Subject: [PATCH 040/107] Added React.forwardRef to API and docs --- content/docs/forwarding-refs.md | 22 +++++++++++++++ content/docs/higher-order-components.md | 28 ++------------------ content/docs/nav.yml | 2 ++ content/docs/reference-react.md | 11 ++++++++ examples/forwarding-refs/fancy-button-ref.js | 15 +++++++++++ examples/forwarding-refs/fancy-button.js | 12 +++++++++ examples/forwarding-refs/log-props-after.js | 26 ++++++++++++++++++ examples/forwarding-refs/log-props-before.js | 16 +++++++++++ examples/reference-react-forward-ref.js | 24 +++++++++++++++++ 9 files changed, 130 insertions(+), 26 deletions(-) create mode 100644 content/docs/forwarding-refs.md create mode 100644 examples/forwarding-refs/fancy-button-ref.js create mode 100644 examples/forwarding-refs/fancy-button.js create mode 100644 examples/forwarding-refs/log-props-after.js create mode 100644 examples/forwarding-refs/log-props-before.js create mode 100644 examples/reference-react-forward-ref.js diff --git a/content/docs/forwarding-refs.md b/content/docs/forwarding-refs.md new file mode 100644 index 00000000..dcebdbfa --- /dev/null +++ b/content/docs/forwarding-refs.md @@ -0,0 +1,22 @@ +--- +id: forwarding-refs +title: Forwarding Refs +permalink: docs/forwarding-refs.html +--- + +Ref forwarding is a technique for passing a [ref](/docs/refs-and-the-dom.html) through a component to one of its descendants. This technique can be particularly useful with [higher-order components](/docs/higher-order-components.html) (also known as HOCs). + +Let's start with an example HOC that logs component props to the console: +`embed:forwarding-refs/log-props-before.js` + +The "logProps" HOC passes all `props` through to the component it wraps, so the rendered output will be the same. For example, we can use this HOC to log all props that get passed to our "fancy button" component: +`embed:forwarding-refs/fancy-button.js` + +There is one caveat to the above example: refs will not get passed through. That's because `ref` is not a prop. Like `key`, it's handled differently by React. If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component. + +This means that refs intended for our `FancyButton` component will actually be attached to the `LogProps` component: +`embed:forwarding-refs/fancy-button-ref.js` + +Fortunately, we can explicitly forward refs to the inner `FancyButton` component using the `React.forwardRef` API. `React.forwardRef` accepts a render function that receives `props` and `ref` parameters and returns a React node. For example: +`embed:forwarding-refs/log-props-after.js` + diff --git a/content/docs/higher-order-components.md b/content/docs/higher-order-components.md index 4f044669..0b5537c5 100644 --- a/content/docs/higher-order-components.md +++ b/content/docs/higher-order-components.md @@ -394,30 +394,6 @@ import MyComponent, { someFunction } from './MyComponent.js'; ### Refs Aren't Passed Through -While the convention for higher-order components is to pass through all props to the wrapped component, it's not possible to pass through refs. That's because `ref` is not really a prop — like `key`, it's handled specially by React. If you add a ref to an element whose component is the result of a HOC, the ref refers to an instance of the outermost container component, not the wrapped component. +While the convention for higher-order components is to pass through all props to the wrapped component, this does not work for refs. That's because `ref` is not really a prop — like `key`, it's handled specially by React. If you add a ref to an element whose component is the result of a HOC, the ref refers to an instance of the outermost container component, not the wrapped component. -If you find yourself facing this problem, the ideal solution is to figure out how to avoid using `ref` at all. Occasionally, users who are new to the React paradigm rely on refs in situations where a prop would work better. - -That said, there are times when refs are a necessary escape hatch — React wouldn't support them otherwise. Focusing an input field is an example where you may want imperative control of a component. In that case, one solution is to pass a ref callback as a normal prop, by giving it a different name: - -```js -function Field({ inputRef, ...rest }) { - return ; -} - -// Wrap Field in a higher-order component -const EnhancedField = enhance(Field); - -// Inside a class component's render method... - { - // This callback gets passed through as a regular prop - this.inputEl = inputEl - }} -/> - -// Now you can call imperative methods -this.inputEl.focus(); -``` - -This is not a perfect solution by any means. We prefer that refs remain a library concern, rather than require you to manually handle them. We are exploring ways to solve this problem so that using a HOC is unobservable. +The solution for this problem is to use the `React.forwardRef` API (introduced with React 16.3). [Learn more about it in the forwarding refs section](/docs/forwarding-refs.html). \ No newline at end of file diff --git a/content/docs/nav.yml b/content/docs/nav.yml index 8bbadf66..2a11519b 100644 --- a/content/docs/nav.yml +++ b/content/docs/nav.yml @@ -66,6 +66,8 @@ title: Web Components - id: higher-order-components title: Higher-Order Components + - id: forwarding-refs + title: Forwarding Refs - id: render-props title: Render Props - id: integrating-with-other-libraries diff --git a/content/docs/reference-react.md b/content/docs/reference-react.md index 0d1597d2..ae0912ae 100644 --- a/content/docs/reference-react.md +++ b/content/docs/reference-react.md @@ -49,6 +49,10 @@ See [Using React without JSX](/docs/react-without-jsx.html) for more information - [`React.Fragment`](#reactfragment) +### Other + +- [`React.forwardRef`](#reactforwardref) + * * * ## Reference @@ -217,3 +221,10 @@ render() { ``` You can also use it with the shorthand `<>` syntax. For more information, see [React v16.2.0: Improved Support for Fragments](/blog/2017/11/28/react-v16.2.0-fragment-support.html). + +### `React.forwardRef` + +`React.forwardRef` accepts a render function that receives `props` and `ref` parameters and returns a React node. Ref forwarding is a technique for passing a [ref](/docs/refs-and-the-dom.html) through a component to one of its descendants. This technique can be particularly useful with [higher-order components](/docs/higher-order-components.html): +`embed:reference-react-forward-ref.js` + +For more information, see [forwarding refs](/docs/forwarding-refs.html). \ No newline at end of file diff --git a/examples/forwarding-refs/fancy-button-ref.js b/examples/forwarding-refs/fancy-button-ref.js new file mode 100644 index 00000000..36e15dd2 --- /dev/null +++ b/examples/forwarding-refs/fancy-button-ref.js @@ -0,0 +1,15 @@ +import FancyButton from './FancyButton'; + +// highlight-next-line +const ref = React.createRef(); + +// The FancyButton component we imported is the LogProps HOC. +// Even though the rendered output will be the same, +// Our ref will point to LogProps instead of the inner FancyButton component! +// This means we can't call e.g. ref.current.focus() +// highlight-range{4} +; diff --git a/examples/forwarding-refs/fancy-button.js b/examples/forwarding-refs/fancy-button.js new file mode 100644 index 00000000..9dcd13e1 --- /dev/null +++ b/examples/forwarding-refs/fancy-button.js @@ -0,0 +1,12 @@ +class FancyButton extends React.Component { + focus() { + // ... + } + + // ... +} + +// Rather than exporting FancyButton, we export LogProps. +// It will render a FancyButton though. +// highlight-next-line +export default logProps(FancyButton); diff --git a/examples/forwarding-refs/log-props-after.js b/examples/forwarding-refs/log-props-after.js new file mode 100644 index 00000000..bab64385 --- /dev/null +++ b/examples/forwarding-refs/log-props-after.js @@ -0,0 +1,26 @@ +function logProps(WrappedComponent) { + class LogProps extends React.Component { + componentWillReceiveProps(nextProps) { + console.log('old props:', this.props); + console.log('new props:', nextProps); + } + + render() { + const {forwardedRef, ...rest} = this.props; + + // Assign the custom prop "forwardedRef" as a ref + // highlight-range{1-3} + return ( + + ); + } + } + + // Intercept the "ref" and pass it as a custom prop, e.g. "forwardedRef" + // highlight-range{1-3} + function logPropsForwardRef(props, ref) { + return ; + } + + return React.forwardRef(logPropsForwardRef); +} diff --git a/examples/forwarding-refs/log-props-before.js b/examples/forwarding-refs/log-props-before.js new file mode 100644 index 00000000..13659449 --- /dev/null +++ b/examples/forwarding-refs/log-props-before.js @@ -0,0 +1,16 @@ +// highlight-next-line +function logProps(WrappedComponent) { + class LogProps extends React.Component { + componentWillReceiveProps(nextProps) { + console.log('old props:', this.props); + console.log('new props:', nextProps); + } + + render() { + // highlight-next-line + return ; + } + } + + return LogProps; +} diff --git a/examples/reference-react-forward-ref.js b/examples/reference-react-forward-ref.js new file mode 100644 index 00000000..59e8a23d --- /dev/null +++ b/examples/reference-react-forward-ref.js @@ -0,0 +1,24 @@ +function enhance(WrappedComponent) { + class Enhanced extends React.Component { + // ... + + render() { + const {forwardedRef, ...rest} = this.props; + + // Assign the custom prop "forwardedRef" as a ref + // highlight-range{1-3} + return ( + + ); + } + } + + // Intercept the "ref" and pass it as a custom prop, e.g. "forwardedRef" + // highlight-range{1-3} + function enhanceForwardRef(props, ref) { + return ; + } + + // highlight-next-line + return React.forwardRef(enhanceForwardRef); +} From 22d0ec128ecf5af877fc60faa7a768b056536319 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 16 Mar 2018 09:42:47 -0700 Subject: [PATCH 042/107] Updated forwardRef example to use named function --- .../16-3-release-blog-post/fancy-button-example.js | 2 +- examples/16-3-release-blog-post/forward-ref-example.js | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/16-3-release-blog-post/fancy-button-example.js b/examples/16-3-release-blog-post/fancy-button-example.js index 22170e52..a5ccb8bf 100644 --- a/examples/16-3-release-blog-post/fancy-button-example.js +++ b/examples/16-3-release-blog-post/fancy-button-example.js @@ -8,7 +8,7 @@ class FancyButton extends React.Component { render() { // highlight-next-line const {label, theme, ...rest} = this.props; - // highlight-range{4} + // highlight-range{5} return ( ); @@ -104,170 +107,8 @@ class MessageList extends React.Component { } ``` -In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Using context, we can pass this through the tree automatically: - -```javascript{6,13-15,21,28-30,40-42} -import PropTypes from 'prop-types'; - -class Button extends React.Component { - render() { - return ( - - ); - } -} - -Button.contextTypes = { - color: PropTypes.string -}; - -class Message extends React.Component { - render() { - return ( -
- {this.props.text} -
- ); - } -} - -class MessageList extends React.Component { - getChildContext() { - return {color: "purple"}; - } - - render() { - const children = this.props.messages.map((message) => - - ); - return
{children}
; - } -} - -MessageList.childContextTypes = { - color: PropTypes.string -}; -``` - -By adding `childContextTypes` and `getChildContext` to `MessageList` (the context provider), React passes the information down automatically and any component in the subtree (in this case, `Button`) can access it by defining `contextTypes`. - -If `contextTypes` is not defined, then `context` will be an empty object. - -> Note: -> -> `React.PropTypes` has moved into a different package since React v15.5. Please use [the `prop-types` library instead](https://www.npmjs.com/package/prop-types) to define `contextTypes`. -> -> We provide [a codemod script](/blog/2017/04/07/react-v15.5.0.html#migrating-from-react.proptypes) to automate the conversion. - -### Parent-Child Coupling - -> This section documents a deprecated API - -Context can also let you build an API where parents and children communicate. For example, one library that works this way is [React Router V4](https://reacttraining.com/react-router): - -```javascript -import { BrowserRouter as Router, Route, Link } from 'react-router-dom'; - -const BasicExample = () => ( - -
-
    -
  • Home
  • -
  • About
  • -
  • Topics
  • -
- -
- - - - -
-
-); -``` - -By passing down some information from the `Router` component, each `Link` and `Route` can communicate back to the containing `Router`. - -Before you build components with an API similar to this, consider if there are cleaner alternatives. For example, you can pass entire React components as props if you'd like to. - -### Referencing Context in Lifecycle Methods - -> This section documents a deprecated API - -If `contextTypes` is defined within a component, the following [lifecycle methods](/docs/react-component.html#the-component-lifecycle) will receive an additional parameter, the `context` object: - -- [`constructor(props, context)`](/docs/react-component.html#constructor) -- [`componentWillReceiveProps(nextProps, nextContext)`](/docs/react-component.html#componentwillreceiveprops) -- [`shouldComponentUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#shouldcomponentupdate) -- [`componentWillUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#componentwillupdate) - -> Note: -> -> As of React 16, `componentDidUpdate` no longer receives `prevContext`. - -### Referencing Context in Stateless Functional Components - -> This section documents a deprecated API - -Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows a `Button` component written as a stateless functional component. - -```javascript -import PropTypes from 'prop-types'; - -const Button = ({children}, context) => - ; - -Button.contextTypes = {color: PropTypes.string}; -``` - -### Updating Context - -> This section documents a deprecated API - -Don't do it. - -React has an API to update context, but it is fundamentally broken and you should not use it. - -The `getChildContext` function will be called when the state or props changes. In order to update data in the context, trigger a local state update with `this.setState`. This will trigger a new context and changes will be received by the children. - -```javascript -import PropTypes from 'prop-types'; - -class MediaQuery extends React.Component { - constructor(props) { - super(props); - this.state = {type:'desktop'}; - } - - getChildContext() { - return {type: this.state.type}; - } - - componentDidMount() { - const checkMediaQuery = () => { - const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile'; - if (type !== this.state.type) { - this.setState({type}); - } - }; - - window.addEventListener('resize', checkMediaQuery); - checkMediaQuery(); - } - - render() { - return this.props.children; - } -} - -MediaQuery.childContextTypes = { - type: PropTypes.string -}; -``` +## Legacy API -The problem is, if a context value provided by component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. This is totally out of control of the components using context, so there's basically no way to reliably update the context. [This blog post](https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076) has a good explanation of why this is a problem and how you might get around it. +> The legacy context API was deprecated in React 16.3 +> +> React previously shipped with an experimental context API. The old API will be supported in all 16.x releases, but applications using it should migrate to the new version. Read the [legacy context docs here](/docs/legacy-context.html). diff --git a/content/docs/legacy-context.md b/content/docs/legacy-context.md new file mode 100644 index 00000000..d9e899f0 --- /dev/null +++ b/content/docs/legacy-context.md @@ -0,0 +1,215 @@ +--- +id: legacy-context +title: Legacy Context +permalink: docs/legacy-context.html +--- + +> This API is deprecated as of React 16.3. +> +> The API will be supported in all 16.x releases, but applications using it should migrate to the [new API](/docs/context.html). The experimental API lacked a safe mechanism to update context. Version 16.3 introduced a new context API that is more efficient and supports both static type checking and deep updates. + +## How To Use Context + +> This section documents a deprecated API. See the [new API](/docs/context.html). + +Suppose you have a structure like: + +```javascript +class Button extends React.Component { + render() { + return ( + + ); + } +} + +class Message extends React.Component { + render() { + return ( +
+ {this.props.text} +
+ ); + } +} + +class MessageList extends React.Component { + render() { + const color = "purple"; + const children = this.props.messages.map((message) => + + ); + return
{children}
; + } +} +``` + +In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Using context, we can pass this through the tree automatically: + +```javascript{6,13-15,21,28-30,40-42} +import PropTypes from 'prop-types'; + +class Button extends React.Component { + render() { + return ( + + ); + } +} + +Button.contextTypes = { + color: PropTypes.string +}; + +class Message extends React.Component { + render() { + return ( +
+ {this.props.text} +
+ ); + } +} + +class MessageList extends React.Component { + getChildContext() { + return {color: "purple"}; + } + + render() { + const children = this.props.messages.map((message) => + + ); + return
{children}
; + } +} + +MessageList.childContextTypes = { + color: PropTypes.string +}; +``` + +By adding `childContextTypes` and `getChildContext` to `MessageList` (the context provider), React passes the information down automatically and any component in the subtree (in this case, `Button`) can access it by defining `contextTypes`. + +If `contextTypes` is not defined, then `context` will be an empty object. + +> Note: +> +> `React.PropTypes` has moved into a different package since React v15.5. Please use [the `prop-types` library instead](https://www.npmjs.com/package/prop-types) to define `contextTypes`. +> +> We provide [a codemod script](/blog/2017/04/07/react-v15.5.0.html#migrating-from-react.proptypes) to automate the conversion. + +### Parent-Child Coupling + +> This section documents a deprecated API. See the [new API](/docs/context.html). + +Context can also let you build an API where parents and children communicate. For example, one library that works this way is [React Router V4](https://reacttraining.com/react-router): + +```javascript +import { BrowserRouter as Router, Route, Link } from 'react-router-dom'; + +const BasicExample = () => ( + +
+
    +
  • Home
  • +
  • About
  • +
  • Topics
  • +
+ +
+ + + + +
+
+); +``` + +By passing down some information from the `Router` component, each `Link` and `Route` can communicate back to the containing `Router`. + +Before you build components with an API similar to this, consider if there are cleaner alternatives. For example, you can pass entire React components as props if you'd like to. + +### Referencing Context in Lifecycle Methods + +> This section documents a deprecated API. See the [new API](/docs/context.html). + +If `contextTypes` is defined within a component, the following [lifecycle methods](/docs/react-component.html#the-component-lifecycle) will receive an additional parameter, the `context` object: + +- [`constructor(props, context)`](/docs/react-component.html#constructor) +- [`componentWillReceiveProps(nextProps, nextContext)`](/docs/react-component.html#componentwillreceiveprops) +- [`shouldComponentUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#shouldcomponentupdate) +- [`componentWillUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#componentwillupdate) + +> Note: +> +> As of React 16, `componentDidUpdate` no longer receives `prevContext`. + +### Referencing Context in Stateless Functional Components + +> This section documents a deprecated API. See the [new API](/docs/context.html). + +Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows a `Button` component written as a stateless functional component. + +```javascript +import PropTypes from 'prop-types'; + +const Button = ({children}, context) => + ; + +Button.contextTypes = {color: PropTypes.string}; +``` + +### Updating Context + +> This section documents a deprecated API. See the [new API](/docs/context.html). + +Don't do it. + +React has an API to update context, but it is fundamentally broken and you should not use it. + +The `getChildContext` function will be called when the state or props changes. In order to update data in the context, trigger a local state update with `this.setState`. This will trigger a new context and changes will be received by the children. + +```javascript +import PropTypes from 'prop-types'; + +class MediaQuery extends React.Component { + constructor(props) { + super(props); + this.state = {type:'desktop'}; + } + + getChildContext() { + return {type: this.state.type}; + } + + componentDidMount() { + const checkMediaQuery = () => { + const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile'; + if (type !== this.state.type) { + this.setState({type}); + } + }; + + window.addEventListener('resize', checkMediaQuery); + checkMediaQuery(); + } + + render() { + return this.props.children; + } +} + +MediaQuery.childContextTypes = { + type: PropTypes.string +}; +``` + +The problem is, if a context value provided by component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. This is totally out of control of the components using context, so there's basically no way to reliably update the context. [This blog post](https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076) has a good explanation of why this is a problem and how you might get around it. \ No newline at end of file From a5022da882fda49e29603a7ad2046b26e88c7a5c Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 20 Mar 2018 18:15:23 -0700 Subject: [PATCH 049/107] Add in-page TOC Also reduce spacing between ul/li tags --- content/docs/context.md | 10 ++++++++++ src/theme.js | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/content/docs/context.md b/content/docs/context.md index 47c0f19a..8fcb2256 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -6,6 +6,16 @@ permalink: docs/context.html Context provides a way to pass data through the component tree without having to pass props down manually at every level. +- [API](#api) + - [React.createContext](#reactcreatecontext) + - [Provider](#provider) + - [Consumer](#consumer) +- [Examples](#examples) + - [Static Context](#static-context) + - [Dynamic Context](#dynamic-context) +- [Motivation](#motivation) +- [Legacy API](#legacy-api) + ## API ### `React.createContext` diff --git a/src/theme.js b/src/theme.js index 9da7e3e4..5fba925d 100644 --- a/src/theme.js +++ b/src/theme.js @@ -336,7 +336,7 @@ const sharedStyles = { }, '& li': { - marginTop: 20, + marginTop: 10, }, '& li.button-newapp': { @@ -345,6 +345,7 @@ const sharedStyles = { '& ol, & ul': { marginLeft: 20, + marginTop: 10, }, }, From fe3d0a449d3f6ae31cdf938086f7f42de871f783 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Tue, 20 Mar 2018 18:29:38 -0700 Subject: [PATCH 050/107] Typo --- content/docs/context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/context.md b/content/docs/context.md index 8fcb2256..706a6370 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -67,7 +67,7 @@ Here is an example illustrating how you might inject a "theme" using context: A more complex example with dynamic values for the theme: -**theme-contex.js** +**theme-context.js** `embed:context/theme-detailed-theme-context.js` **themed-button.js** From 808e5bddaff2685186aec1389130d00408743dfb Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Wed, 21 Mar 2018 01:28:01 -0700 Subject: [PATCH 051/107] Rephrase and reorganize - Move Motivation to top @bvaughn - Copy in some Motivation text from the RFC for the intro para - Update examples - Remove state from simple example - Remove "random color" example; just toggle a theme variable instead - Update highlights --- content/docs/context.md | 67 +++++-------------- content/docs/legacy-context.md | 8 ++- examples/context/motivation.js | 33 +++++++++ examples/context/theme-detailed-app.js | 33 ++++----- .../context/theme-detailed-theme-context.js | 14 +++- .../context/theme-detailed-themed-button.js | 3 +- examples/context/theme-example.js | 37 ++++++---- 7 files changed, 107 insertions(+), 88 deletions(-) create mode 100644 examples/context/motivation.js diff --git a/content/docs/context.md b/content/docs/context.md index 706a6370..fd3e814b 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -6,6 +6,9 @@ permalink: docs/context.html Context provides a way to pass data through the component tree without having to pass props down manually at every level. +Typically, data in a React application is passed top-down (parent to child) via props. But sometimes it's useful to pass values through multiple levels without adding props to every intermediate component. Examples include a language preference, or a UI theme. Many components may rely on those but you don't want to have to pass a locale prop and a theme prop through every level of the tree. + +- [Motivation](#motivation) - [API](#api) - [React.createContext](#reactcreatecontext) - [Provider](#provider) @@ -13,21 +16,26 @@ Context provides a way to pass data through the component tree without having to - [Examples](#examples) - [Static Context](#static-context) - [Dynamic Context](#dynamic-context) -- [Motivation](#motivation) - [Legacy API](#legacy-api) + +## Motivation + +Context is designed to relieve the pain of passing props down through a deeply nested component tree. For example, in the code below we manually thread through a color prop in order to style the Button and Message components. Using context, we can avoid passing props through intermediate elements. + +`embed:context/motivation.js` + ## API ### `React.createContext` ```js -const {Provider, Consumer} = React.createContext([default]); +const {Provider, Consumer} = React.createContext(defaultValue); ``` Creates a `{ Provider, Consumer }` pair. -Takes one argument, the default context that Consumers will receive when they don't have a matching Provider. - +Optionally accepts a default value to be passed to Consumers without a Provider ancestor. ### `Provider` @@ -37,7 +45,7 @@ Takes one argument, the default context that Consumers will receive when they do A React component that allows Consumers to subscribe to context changes. -Takes one prop, `value`, which will be passed to the [render prop](/docs/render-props.html) of child Consumers for the matching context anywhere in the component tree. One Provider can be connected to many Consumers. +Accepts a `value` prop to be passed to Consumers that are descendants of this Provider. One Provider can be connected to many Consumers. Providers can be nested to override values deeper within the tree. ### `Consumer` @@ -47,12 +55,12 @@ Takes one prop, `value`, which will be passed to the [render prop](/docs/render- ``` -A React component that subscribes to context changes. +A React component that subscribes to context changes. -Takes a function as the `children` prop that receives the `value` prop of the matching Provider. This function will be called whenever the Provider's value is updated. +Requires a [function as a child](/docs/render-props.html#using-props-other-than-render). This function receives the current context value and returns a React node, and will be called whenever the Provider's value is updated. > Note: -> +> > For more information about this pattern, see [render props](/docs/render-props.html). ## Examples @@ -76,49 +84,8 @@ A more complex example with dynamic values for the theme: **app.js** `embed:context/theme-detailed-app.js` -## Motivation - -Context is designed to relieve the pain of passing props down through a deeply nested component tree. For example, in the code below we manually thread through a color prop in order to style the Button and Message components. Using context, we can avoid passing props through intermediate elements. - -```js -class Button extends React.Component { - render() { - return ( - - ); - } -} - -class Message extends React.Component { - render() { - return ( -
- {/* - The Message component must take `color` as as prop to pass it to the - Button. Using context, the Button could connect to the color context - on its own. - */} - {this.props.text} -
- ); - } -} - -class MessageList extends React.Component { - render() { - const color = "purple"; - const children = this.props.messages.map((message) => - - ); - return
{children}
; - } -} -``` - ## Legacy API -> The legacy context API was deprecated in React 16.3 +> The legacy context API was deprecated in React 16.3 and will be removed in version 17. > > React previously shipped with an experimental context API. The old API will be supported in all 16.x releases, but applications using it should migrate to the new version. Read the [legacy context docs here](/docs/legacy-context.html). diff --git a/content/docs/legacy-context.md b/content/docs/legacy-context.md index d9e899f0..8da900b6 100644 --- a/content/docs/legacy-context.md +++ b/content/docs/legacy-context.md @@ -4,9 +4,11 @@ title: Legacy Context permalink: docs/legacy-context.html --- -> This API is deprecated as of React 16.3. -> -> The API will be supported in all 16.x releases, but applications using it should migrate to the [new API](/docs/context.html). The experimental API lacked a safe mechanism to update context. Version 16.3 introduced a new context API that is more efficient and supports both static type checking and deep updates. +> Deprecation Warning +> +> The legacy API has been deprecated and will be removed in version 17. +> Use the [new context API](/docs/context.html) introduced with version 16.3. +> The legacy API will continue working for all 16.x releases. ## How To Use Context diff --git a/examples/context/motivation.js b/examples/context/motivation.js new file mode 100644 index 00000000..1e6ed885 --- /dev/null +++ b/examples/context/motivation.js @@ -0,0 +1,33 @@ +class Button extends React.Component { + render() { + return ( + + ); + } +} + +class Message extends React.Component { + render() { + // highlight-range{1-3} + // The Message component must take `color` as as prop to pass it + // to the Button. Using context, the Button could connect to the + // color context on its own. + return ( +
+ {this.props.text} +
+ ); + } +} + +class MessageList extends React.Component { + render() { + const color = "purple"; + const children = this.props.messages.map((message) => + + ); + return
{children}
; + } +} diff --git a/examples/context/theme-detailed-app.js b/examples/context/theme-detailed-app.js index 4cbd4669..e1ca8345 100644 --- a/examples/context/theme-detailed-app.js +++ b/examples/context/theme-detailed-app.js @@ -1,34 +1,27 @@ -import ThemeContext from './theme-context'; +import ThemeContext, {themes} from './theme-context'; import ThemedButton from './button'; class App extends React.Component { state = { - theme: { - highlight: 'blue', - accent: 'purple', - }, + theme: themes.light, }; - changeHighlightColor = () => { - const colors = ['red', 'blue', 'green']; - const randomColor = - colors[Math.floor(Math.random() * 3)]; - this.setState({ - theme: { - ...this.state.theme, - highlight: randomColor, - }, - }); + toggleTheme = () => { + this.setState(state => ({ + theme: + state.theme === themes.dark + ? themes.light + : themes.dark, + })); }; render() { + //highlight-range{2,6} return ( -
- - Change Theme - -
+ + Change Theme +
); } diff --git a/examples/context/theme-detailed-theme-context.js b/examples/context/theme-detailed-theme-context.js index 75af25f8..d8051fab 100644 --- a/examples/context/theme-detailed-theme-context.js +++ b/examples/context/theme-detailed-theme-context.js @@ -1,5 +1,15 @@ -const defaultTheme = {highlight: 'blue', accent: 'purple'}; +export const themes = { + light: { + foreground: '#ffffff', + background: '#222222', + }, + dark: { + foreground: '#000000', + background: '#eeeeee', + }, +}; -const ThemeContext = React.createContext(defaultTheme); +// highlight-next-line +const ThemeContext = React.createContext(themes.dark); export default ThemeContext; diff --git a/examples/context/theme-detailed-themed-button.js b/examples/context/theme-detailed-themed-button.js index 6ec33b5b..10c1d922 100644 --- a/examples/context/theme-detailed-themed-button.js +++ b/examples/context/theme-detailed-themed-button.js @@ -1,13 +1,14 @@ import ThemeContext from './theme-context'; class ThemedButton extends React.Component { + // highlight-range{3-10} render() { return ( {theme => ( +

{this.props.text}

+ ); } @@ -24,10 +25,10 @@ class Message extends React.Component { class MessageList extends React.Component { render() { - const color = "purple"; - const children = this.props.messages.map((message) => + const color = 'purple'; + const children = this.props.messages.map(message => ( - ); + )); return
{children}
; } } diff --git a/examples/context/theme-detailed-app.js b/examples/context/theme-detailed-app.js index e1ca8345..1b57e15d 100644 --- a/examples/context/theme-detailed-app.js +++ b/examples/context/theme-detailed-app.js @@ -1,4 +1,4 @@ -import ThemeContext, {themes} from './theme-context'; +import {ThemeContext, themes} from './theme-context'; import ThemedButton from './button'; class App extends React.Component { diff --git a/examples/context/theme-detailed-theme-context.js b/examples/context/theme-detailed-theme-context.js index d8051fab..c0f30d95 100644 --- a/examples/context/theme-detailed-theme-context.js +++ b/examples/context/theme-detailed-theme-context.js @@ -10,6 +10,6 @@ export const themes = { }; // highlight-next-line -const ThemeContext = React.createContext(themes.dark); - -export default ThemeContext; +export const ThemeContext = React.createContext( + themes.dark +); diff --git a/examples/context/theme-detailed-themed-button.js b/examples/context/theme-detailed-themed-button.js index 10c1d922..aa36ee77 100644 --- a/examples/context/theme-detailed-themed-button.js +++ b/examples/context/theme-detailed-themed-button.js @@ -1,4 +1,4 @@ -import ThemeContext from './theme-context'; +import {ThemeContext} from './theme-context'; class ThemedButton extends React.Component { // highlight-range{3-10} From 291b2fdeb8bd707d7f28231300fdf2903b45acd9 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Wed, 21 Mar 2018 10:03:08 -0700 Subject: [PATCH 053/107] Wording tweaks --- content/docs/context.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/context.md b/content/docs/context.md index fd3e814b..1463720e 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -6,7 +6,7 @@ permalink: docs/context.html Context provides a way to pass data through the component tree without having to pass props down manually at every level. -Typically, data in a React application is passed top-down (parent to child) via props. But sometimes it's useful to pass values through multiple levels without adding props to every intermediate component. Examples include a language preference, or a UI theme. Many components may rely on those but you don't want to have to pass a locale prop and a theme prop through every level of the tree. +In a typical React application, data is passed top-down (parent to child) via props, but this can be cumbersome for certain types of props (e.g. locale preference, UI theme) that are required by many components within an application. Context provides a way to share values like this between components without having to explicitly pass a prop through every level of the tree. - [Motivation](#motivation) - [API](#api) @@ -57,7 +57,7 @@ Accepts a `value` prop to be passed to Consumers that are descendants of this Pr A React component that subscribes to context changes. -Requires a [function as a child](/docs/render-props.html#using-props-other-than-render). This function receives the current context value and returns a React node, and will be called whenever the Provider's value is updated. +Requires a [function as a child](/docs/render-props.html#using-props-other-than-render). This function receives the current context value and returns a React node. It will be called whenever the Provider's value is updated. > Note: > From 6aa199516d515e95ad8191902e9b95f19cd7f28b Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Wed, 21 Mar 2018 10:04:11 -0700 Subject: [PATCH 054/107] Add solution to motivation problem --- content/docs/context.md | 8 +++- .../{motivation.js => motivation-problem.js} | 0 examples/context/motivation-solution.js | 42 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) rename examples/context/{motivation.js => motivation-problem.js} (100%) create mode 100644 examples/context/motivation-solution.js diff --git a/content/docs/context.md b/content/docs/context.md index 1463720e..2b9ccfdd 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -21,9 +21,13 @@ In a typical React application, data is passed top-down (parent to child) via pr ## Motivation -Context is designed to relieve the pain of passing props down through a deeply nested component tree. For example, in the code below we manually thread through a color prop in order to style the Button and Message components. Using context, we can avoid passing props through intermediate elements. +Context is designed to relieve the pain of passing props down through a deeply nested component tree. For example, in the code below we manually thread through a color prop in order to style the Button and Message components: -`embed:context/motivation.js` +`embed:context/motivation-problem.js` + +Using context, we can avoid passing props through intermediate elements: + +`embed:context/motivation-solution.js` ## API diff --git a/examples/context/motivation.js b/examples/context/motivation-problem.js similarity index 100% rename from examples/context/motivation.js rename to examples/context/motivation-problem.js diff --git a/examples/context/motivation-solution.js b/examples/context/motivation-solution.js new file mode 100644 index 00000000..fbb6ac59 --- /dev/null +++ b/examples/context/motivation-solution.js @@ -0,0 +1,42 @@ +const ColorContext = React.createContext(); + +class Button extends React.Component { + render() { + // highlight-range{2-8} + return ( + + {color => ( + + )} + + ); + } +} + +class Message extends React.Component { + render() { + return ( +
+

{this.props.text}

+ +
+ ); + } +} + +class MessageList extends React.Component { + render() { + const color = 'purple'; + const children = this.props.messages.map(message => ( + + )); + // highlight-range{2-4} + return ( + + {children} + + ); + } +} From 7c6688c12cf1610ce99d61ab34f13746e3f981a5 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Wed, 21 Mar 2018 10:16:38 -0700 Subject: [PATCH 055/107] Highlight createContext() --- examples/context/motivation-solution.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/context/motivation-solution.js b/examples/context/motivation-solution.js index fbb6ac59..76bf72cc 100644 --- a/examples/context/motivation-solution.js +++ b/examples/context/motivation-solution.js @@ -1,3 +1,4 @@ +// highlight-range{1} const ColorContext = React.createContext(); class Button extends React.Component { From b49f99b7d1d6941e7d101eac7e93d7e4f157c939 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Wed, 21 Mar 2018 12:16:23 -0700 Subject: [PATCH 056/107] Highlight whole createContext() call --- examples/context/theme-detailed-theme-context.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/context/theme-detailed-theme-context.js b/examples/context/theme-detailed-theme-context.js index c0f30d95..80dd489a 100644 --- a/examples/context/theme-detailed-theme-context.js +++ b/examples/context/theme-detailed-theme-context.js @@ -9,7 +9,7 @@ export const themes = { }, }; -// highlight-next-line +// highlight-range{1-3} export const ThemeContext = React.createContext( themes.dark ); From 2f9b77a980c19ba2c3e61d12dffbcac1b60310ec Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 22 Mar 2018 08:10:25 -0700 Subject: [PATCH 057/107] 16.4 -> 16.x --- content/blog/2018-03-20-react-v-16-3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/2018-03-20-react-v-16-3.md b/content/blog/2018-03-20-react-v-16-3.md index 3c71e7ed..13fb76b5 100644 --- a/content/blog/2018-03-20-react-v-16-3.md +++ b/content/blog/2018-03-20-react-v-16-3.md @@ -68,7 +68,7 @@ We recognize that this change will impact many existing components. (At Facebook > **Note:** > -> Deprecation warnings will be enabled in version 16.4, **but the legacy lifecycles will continue to work until version 17**. +> Deprecation warnings will be enabled with a future 16.x release, **but the legacy lifecycles will continue to work until version 17**. > > Even in version 17, it will still be possible to use them, but they will be aliased with an "UNSAFE_" prefix to indicate that they might cause issues. We have also prepared an [automated script to rename them](https://github.com/reactjs/react-codemod#rename-unsafe-lifecycles) in existing code. From e9ae68f55b55c5a0c7b74c6af00e2e5c5b3d99a6 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Thu, 22 Mar 2018 20:58:22 -0700 Subject: [PATCH 058/107] remove confusing {} --- content/docs/context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/context.md b/content/docs/context.md index 2b9ccfdd..55997c8d 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -55,7 +55,7 @@ Accepts a `value` prop to be passed to Consumers that are descendants of this Pr ```js - { value => { /* render something based on the context value */ } } + {value => /* render something based on the context value */} ``` From 53d604fd3a7209b2a9c1293ce094b867b7d8983d Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Thu, 22 Mar 2018 20:58:50 -0700 Subject: [PATCH 059/107] ~deprecated~ legacy --- content/docs/context.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/context.md b/content/docs/context.md index 55997c8d..2f0b3c60 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -90,6 +90,6 @@ A more complex example with dynamic values for the theme: ## Legacy API -> The legacy context API was deprecated in React 16.3 and will be removed in version 17. +> The old context API was marked as legacy in React 16.3 and will be removed in version 17. > > React previously shipped with an experimental context API. The old API will be supported in all 16.x releases, but applications using it should migrate to the new version. Read the [legacy context docs here](/docs/legacy-context.html). From fec6d6c141def553e71aa189da30aa687db31035 Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Thu, 22 Mar 2018 21:01:59 -0700 Subject: [PATCH 060/107] Add mutliple contexts example --- content/docs/context.md | 3 +++ examples/context/multiple-contexts.js | 36 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 examples/context/multiple-contexts.js diff --git a/content/docs/context.md b/content/docs/context.md index 2f0b3c60..7c158a4e 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -88,6 +88,9 @@ A more complex example with dynamic values for the theme: **app.js** `embed:context/theme-detailed-app.js` +## Consuming Multiple Contexts + +`embed:context/multiple-contexts.js` ## Legacy API > The old context API was marked as legacy in React 16.3 and will be removed in version 17. diff --git a/examples/context/multiple-contexts.js b/examples/context/multiple-contexts.js new file mode 100644 index 00000000..494e8cd4 --- /dev/null +++ b/examples/context/multiple-contexts.js @@ -0,0 +1,36 @@ +// Create a theme context, defaulting to light theme +// highlight-next-line +const ThemeContext = React.createContext('light'); + +// Signed-in user context +const UserContext = React.createContext(); + +class App extends React.Component { + static propTypes = { + theme: PropTypes.string, + signedInUser: PropTypes.shape({ + id: number, + name: string, + avatar: string, + }), + }; + + render() { + return ( + + + + {theme => ( + + {user => ( + + )} + + )} + + + + ); + } +} From 7b5764fed5c35cf7b3fcc5df480abe56298852bd Mon Sep 17 00:00:00 2001 From: Alex Krolick Date: Thu, 22 Mar 2018 21:15:40 -0700 Subject: [PATCH 061/107] Add ref forwarding, lifecycle examples --- content/docs/context.md | 12 ++++++++++++ examples/context/forwarding-refs.js | 11 +++++++++++ examples/context/lifecycles.js | 20 ++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 examples/context/forwarding-refs.js create mode 100644 examples/context/lifecycles.js diff --git a/content/docs/context.md b/content/docs/context.md index 7c158a4e..4441118d 100644 --- a/content/docs/context.md +++ b/content/docs/context.md @@ -16,6 +16,9 @@ In a typical React application, data is passed top-down (parent to child) via pr - [Examples](#examples) - [Static Context](#static-context) - [Dynamic Context](#dynamic-context) + - [Consuming Multiple Contexts](#consuming-multiple-contexts) + - [Accessing Context in Lifecycle Methods](#accessing-context-in-lifecycle-methods) + - [Forwarding Refs to Context Consumers](#forwarding-refs-to-context-consumers) - [Legacy API](#legacy-api) @@ -91,6 +94,15 @@ A more complex example with dynamic values for the theme: ## Consuming Multiple Contexts `embed:context/multiple-contexts.js` + +## Accessing Context in Lifecycle Methods + +`embed:context/lifecycles.js` + +## Forwarding Refs to Context Consumers + +`embed:context/forwarding-refs.js` + ## Legacy API > The old context API was marked as legacy in React 16.3 and will be removed in version 17. diff --git a/examples/context/forwarding-refs.js b/examples/context/forwarding-refs.js new file mode 100644 index 00000000..e23ae77f --- /dev/null +++ b/examples/context/forwarding-refs.js @@ -0,0 +1,11 @@ +const Button = ({theme, children}) => ( + +); + +export default React.forwardRef((props, ref) => ( + + {theme => + ); + } +} + +export default props => ( + + {theme => - ); - } -} +const ThemedButton = props => { + //highlight-range{1} + return - - ); - } -} +// An intermediate component +const Toolbar = props => { + // highlight-range{1-2,5} + // The Toolbar component must take an extra theme prop + // and pass it to the ThemedButton + return ( +
+ +
+ ); +}; -class MessageList extends React.Component { +class App extends React.Component { render() { - const color = 'purple'; - const children = this.props.messages.map(message => ( - - )); - return
{children}
; + // highlight-range{1} + return ; } } diff --git a/examples/context/motivation-solution.js b/examples/context/motivation-solution.js index 76bf72cc..d1922f6d 100644 --- a/examples/context/motivation-solution.js +++ b/examples/context/motivation-solution.js @@ -1,43 +1,31 @@ -// highlight-range{1} -const ColorContext = React.createContext(); +// Create a theme context, defaulting to light theme +// highlight-next-line +const ThemeContext = React.createContext('light'); -class Button extends React.Component { - render() { - // highlight-range{2-8} - return ( - - {color => ( - - )} - - ); - } -} +// highlight-range{1,3-5} +// The ThemedButton receives the theme from context +const ThemedButton = props => ( + + {theme => - - ); - } -} +// An intermediate component +const Toolbar = props => { + return ( +
+ +
+ ); +}; -class MessageList extends React.Component { +class App extends React.Component { render() { - const color = 'purple'; - const children = this.props.messages.map(message => ( - - )); - // highlight-range{2-4} + // highlight-range{2,4} return ( - - {children} - + + + ); } } diff --git a/examples/context/theme-detailed-app.js b/examples/context/theme-detailed-app.js index 1b57e15d..07b3de48 100644 --- a/examples/context/theme-detailed-app.js +++ b/examples/context/theme-detailed-app.js @@ -1,6 +1,15 @@ import {ThemeContext, themes} from './theme-context'; import ThemedButton from './button'; +// An intermediate component that uses the ThemedButton +const Toolbar = props => { + return ( + + Change Theme + + ); +}; + class App extends React.Component { state = { theme: themes.light, @@ -16,13 +25,20 @@ class App extends React.Component { }; render() { - //highlight-range{2,6} + //highlight-range{1-3} + // The ThemedButton button inside the ThemeProvider + // uses the theme from state while the one outside uses + // the default dark theme + //highlight-range{3-5,7} return ( - - - Change Theme - - +
+ + + +
+ +
+
); } } diff --git a/examples/context/theme-example.js b/examples/context/theme-example.js deleted file mode 100644 index d96e4765..00000000 --- a/examples/context/theme-example.js +++ /dev/null @@ -1,55 +0,0 @@ -// Create a theme context, defaulting to light theme -// highlight-next-line -const ThemeContext = React.createContext('light'); - -class ThemeProvider extends React.Component { - render() { - // highlight-range{2-4} - return ( - - {this.props.children} - - ); - } -} - -class ThemedButton extends React.Component { - render() { - //highlight-range{2-4} - return ( - - {theme => ); +// highlight-range{1,3} export default React.forwardRef((props, ref) => ( {theme => -); - -// highlight-range{1,3} -export default React.forwardRef((props, ref) => ( - - {theme =>