From eec235f302e7aa55211e5e2dabe8331d23670e3d Mon Sep 17 00:00:00 2001 From: ntban15 Date: Sun, 24 Feb 2019 17:01:47 +0700 Subject: [PATCH 01/30] Translate Handling Events --- content/docs/handling-events.md | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/content/docs/handling-events.md b/content/docs/handling-events.md index a8d3a1f51..c885e689a 100644 --- a/content/docs/handling-events.md +++ b/content/docs/handling-events.md @@ -1,6 +1,6 @@ --- id: handling-events -title: Handling Events +title: Bắt Sự kiện permalink: docs/handling-events.html prev: state-and-lifecycle.html next: conditional-rendering.html @@ -8,12 +8,12 @@ redirect_from: - "docs/events-ko-KR.html" --- -Handling events with React elements is very similar to handling events on DOM elements. There are some syntactic differences: +Việc bắt sự kiện của những element React rất giống với những element DOM. Có một số khác biệt về cú pháp như: -* React events are named using camelCase, rather than lowercase. -* With JSX you pass a function as the event handler, rather than a string. +* Những sự kiện của React được đặt tên theo dạng camelCase, thay vì lowercase. +* Với JSX, bạn có thể sử dụng hàm để bắt sự kiện thay vì phải truyền vào một chuỗi. -For example, the HTML: +Ví dụ, đoạn HTML sau: ```html ``` -is slightly different in React: +sẽ có đôi chút khác biệt trong React: ```js{1} ``` -Another difference is that you cannot return `false` to prevent default behavior in React. You must call `preventDefault` explicitly. For example, with plain HTML, to prevent the default link behavior of opening a new page, you can write: +Một điểm khác biệt nữa trong React là bạn không thể trả về `false` để chặn những hành vi mặc định mà phải gọi `preventDefault` trực tiếp. Lấy ví dụ với đoạn HTML sau, để chặn hành vi mặc định của đường dẫn là mở trang mới, bạn có thể viết: ```html @@ -37,7 +37,7 @@ Another difference is that you cannot return `false` to prevent default behavior ``` -In React, this could instead be: +Còn trong React, bạn có thể làm như thế này: ```js{2-5,8} function ActionLink() { @@ -54,11 +54,11 @@ function ActionLink() { } ``` -Here, `e` is a synthetic event. React defines these synthetic events according to the [W3C spec](https://www.w3.org/TR/DOM-Level-3-Events/), so you don't need to worry about cross-browser compatibility. See the [`SyntheticEvent`](/docs/events.html) reference guide to learn more. +Ở đây, `e` là một sự kiện ảo. React định nghĩa những sự kiện ảo này dựa trên [chuẩn W3C](https://www.w3.org/TR/DOM-Level-3-Events/), nên bạn không cần lo lắng về sự tương thích giữa những browser. Hãy tham khảo tài liệu về [`SyntheticEvent`](/docs/events.html) để tìm hiểu thêm. -When using React you should generally not need to call `addEventListener` to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered. +Khi làm việc với React, bạn thường không phải gọi `addEventListener` để gắn listener cho element DOM khi nó được khởi tạo. Thay vào đó, bạn chỉ cần gắn listener ngay lần đầu element được render. -When you define a component using an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes), a common pattern is for an event handler to be a method on the class. For example, this `Toggle` component renders a button that lets the user toggle between "ON" and "OFF" states: +Khi bạn định nghĩa component bằng [class ES6](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes), một mẫu thiết kế phổ biến là sử dụng phương thức của class để bắt sự kiện. Ví dụ, component `Toggle` dưới đây render một chiếc nút để người dùng thay đổi giữa state “ON” và “OFF": ```js{6,7,10-14,18} class Toggle extends React.Component { @@ -66,7 +66,7 @@ class Toggle extends React.Component { super(props); this.state = {isToggleOn: true}; - // This binding is necessary to make `this` work in the callback + // Phép ràng buộc (bind) này là cần thiết để `this` hoạt động trong callback this.handleClick = this.handleClick.bind(this); } @@ -91,18 +91,18 @@ ReactDOM.render( ); ``` -[**Try it on CodePen**](http://codepen.io/gaearon/pen/xEmzGg?editors=0010) +[**Thử trên CodePen**](http://codepen.io/gaearon/pen/xEmzGg?editors=0010) -You have to be careful about the meaning of `this` in JSX callbacks. In JavaScript, class methods are not [bound](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind) by default. If you forget to bind `this.handleClick` and pass it to `onClick`, `this` will be `undefined` when the function is actually called. +Bạn phải cẩn thận về ý nghĩa của `this` trong những callback JSX. Trong JavaScript, những phương thức của class mặc định không bị [ràng buộc](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind). Nếu bạn quên ràng buộc `this.handleClick` và truyền nó vào `onClick`, `this` sẽ có giá trị là `undefined` khi phương thức này được thực thi. -This is not React-specific behavior; it is a part of [how functions work in JavaScript](https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/). Generally, if you refer to a method without `()` after it, such as `onClick={this.handleClick}`, you should bind that method. +Đây không phải là tính chất của React mà là một phần trong [cách những hàm JavaScript hoạt động](https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/). Thông thường, nếu bạn trỏ tới phương thức mà không có `()` theo sau như `onClick={this.handleClick}`, bạn nên ràng buộc phương thức đó. -If calling `bind` annoys you, there are two ways you can get around this. If you are using the experimental [public class fields syntax](https://babeljs.io/docs/plugins/transform-class-properties/), you can use class fields to correctly bind callbacks: +Nếu bạn thấy việc gọi `bind` phiền phức thì có hai giải pháp. Trong trường hợp bạn đang sử dụng [cú pháp thuộc tính class public](https://babeljs.io/docs/plugins/transform-class-properties/) thử nghiệm, bạn có thể dùng những thuộc tính class để ràng buộc callback một cách chính xác: ```js{2-6} class LoggingButton extends React.Component { - // This syntax ensures `this` is bound within handleClick. - // Warning: this is *experimental* syntax. + // Cú pháp này đảm bảo `this` được ràng buộc trong handleClick. + // Cảnh báo: đây là cú pháp *thử nghiệm*. handleClick = () => { console.log('this is:', this); } @@ -117,9 +117,9 @@ class LoggingButton extends React.Component { } ``` -This syntax is enabled by default in [Create React App](https://github.com/facebookincubator/create-react-app). +Cú pháp này được bật theo mặc định trong [Create React App](https://github.com/facebookincubator/create-react-app). -If you aren't using class fields syntax, you can use an [arrow function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) in the callback: +Nếu bạn không sử dụng cú pháp thuộc tính class, bạn có thể dùng [hàm rút gọn](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Functions/Arrow_functions) trong callback: ```js{7-9} class LoggingButton extends React.Component { @@ -128,7 +128,7 @@ class LoggingButton extends React.Component { } render() { - // This syntax ensures `this` is bound within handleClick + // Cú pháp này đảm bảo `this` được ràng buộc trong handleClick return ( ``` -The above two lines are equivalent, and use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) and [`Function.prototype.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) respectively. +Hai dòng code trên là tương đương, và lần lượt sử dụng [hàm rút gọn](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Functions/Arrow_functions) và [`Function.prototype.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind). -In both cases, the `e` argument representing the React event will be passed as a second argument after the ID. With an arrow function, we have to pass it explicitly, but with `bind` any further arguments are automatically forwarded. +Trong cả hai trường hợp, tham số `e`, đại diện cho sự kiện React, sẽ được truyền là tham số thứ hai sau số định danh. Với hàm rút gọn, chúng ta phải truyền nó trực tiếp, nhưng với `bind` thì những tham số còn lại sẽ tự động nối tiếp. From 3bdeb0a15c3eca9748f4c054423324705bd151b5 Mon Sep 17 00:00:00 2001 From: ntban15 Date: Thu, 28 Feb 2019 09:51:45 +0700 Subject: [PATCH 02/30] Minor fixes + Update 'warning' + Update MDN doc for Classes --- content/docs/handling-events.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/handling-events.md b/content/docs/handling-events.md index a508c9c79..65d595090 100644 --- a/content/docs/handling-events.md +++ b/content/docs/handling-events.md @@ -58,7 +58,7 @@ function ActionLink() { Khi làm việc với React, bạn thường không phải gọi `addEventListener` để gắn listener cho element DOM khi nó được khởi tạo. Thay vào đó, bạn chỉ cần gắn listener ngay lần đầu element được render. -Khi bạn định nghĩa component bằng [class ES6](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes), một mẫu thiết kế phổ biến là sử dụng phương thức của class để bắt sự kiện. Ví dụ, component `Toggle` dưới đây render một chiếc nút để người dùng thay đổi giữa state “ON” và “OFF": +Khi bạn định nghĩa component bằng [class ES6](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Classes), một mẫu thiết kế phổ biến là sử dụng phương thức của class để bắt sự kiện. Ví dụ, component `Toggle` dưới đây render một chiếc nút để người dùng thay đổi giữa state “ON” và “OFF": ```js{6,7,10-14,18} class Toggle extends React.Component { @@ -102,7 +102,7 @@ Nếu bạn thấy việc gọi `bind` phiền phức thì có hai giải pháp. ```js{2-6} class LoggingButton extends React.Component { // Cú pháp này đảm bảo `this` được ràng buộc trong handleClick. - // Cảnh báo: đây là cú pháp *thử nghiệm*. + // Lưu ý: đây là cú pháp *thử nghiệm*. handleClick = () => { console.log('this is:', this); } From 75a259881d3b3c241ddd12bc9c299a40aefaa047 Mon Sep 17 00:00:00 2001 From: Sophie Alpert Date: Fri, 1 Mar 2019 17:27:47 -0800 Subject: [PATCH 03/30] Update tutorial.md --- content/tutorial/tutorial.md | 64 +++++++++++++----------------------- 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/content/tutorial/tutorial.md b/content/tutorial/tutorial.md index 9e1e58872..1c69ae99f 100644 --- a/content/tutorial/tutorial.md +++ b/content/tutorial/tutorial.md @@ -31,8 +31,6 @@ The tutorial is divided into several sections: You don't have to complete all of the sections at once to get the value out of this tutorial. Try to get as far as you can -- even if it's one or two sections. -It's fine to copy and paste code as you're following along the tutorial, but we recommend to type it by hand. This will help you develop a muscle memory and a stronger understanding. - ### What Are We Building? {#what-are-we-building} In this tutorial, we'll show how to build an interactive tic-tac-toe game with React. @@ -188,7 +186,9 @@ The Square component renders a single ` + + + ); +} +``` + +If you first click "Show alert" and then increment the counter, the alert will show the `count` variable **at the time you clicked the "Show alert" button**. This prevents bugs caused by the code assuming props and state don't change. + +If you intentionally want to read the *latest* state from some asynchronous callback, you could keep it in [a ref](/docs/hooks-faq.html#is-there-something-like-instance-variables), mutate it, and read from it. + +Finally, another possible reason you're seeing stale props or state is if you use the "dependency array" optimization but didn't correctly specify all the dependencies. For example, if an effect specifies `[]` as the second argument but reads `someProp` inside, it will keep "seeing" the initial value of `someProp`. The solution is to either remove the dependency array, or to fix it. Here's [how you can deal with functions](#is-it-safe-to-omit-functions-from-the-list-of-dependencies), and here's [other common strategies](#what-can-i-do-if-my-effect-dependencies-change-too-often) to run effects less often without incorrectly skipping dependencies. + +>Note +> +>We provide an [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) ESLint rule as a part of the [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation) package. It warns when dependencies are specified incorrectly and suggests a fix. + ### How do I implement `getDerivedStateFromProps`? {#how-do-i-implement-getderivedstatefromprops} While you probably [don't need it](/blog/2018/06/07/you-probably-dont-need-derived-state.html), in rare cases that you do (such as implementing a `` component), you can update the state right during rendering. React will re-run the component with updated state immediately after exiting the first render so it wouldn't be expensive. @@ -416,6 +462,207 @@ If you're not familiar with this syntax, check out the [explanation](/docs/hooks Yes. See [conditionally firing an effect](/docs/hooks-reference.html#conditionally-firing-an-effect). Note that forgetting to handle updates often [introduces bugs](/docs/hooks-effect.html#explanation-why-effects-run-on-each-update), which is why this isn't the default behavior. +### Is it safe to omit functions from the list of dependencies? {#is-it-safe-to-omit-functions-from-the-list-of-dependencies} + +Generally speaking, no. + +```js{3,8} +function Example() { + function doSomething() { + console.log(someProp); + } + + useEffect(() => { + doSomething(); + }, []); // 🔴 This is not safe (it calls `doSomething` which uses `someProp`) +} +``` + +It's difficult to remember which props or state are used by functions outside of the effect. This is why **usually you'll want to declare functions needed by an effect *inside* of it.** Then it's easy to see what values from the component scope that effect depends on: + +```js{4,8} +function Example() { + useEffect(() => { + function doSomething() { + console.log(someProp); + } + + doSomething(); + }, [someProp]); // ✅ OK (our effect only uses `someProp`) +} +``` + +If after that we still don't use any values from the component scope, it's safe to specify `[]`: + +```js{7} +useEffect(() => { + function doSomething() { + console.log('hello'); + } + + doSomething(); +}, []); // ✅ OK in this example because we don't use *any* values from component scope +``` + +Depending on your use case, there are a few more options described below. + +>Note +> +>We provide the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) ESLint rule as a part of the [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation) package. It help you find components that don't handle updates consistently. + +Let's see why this matters. + +If you specify a [list of dependencies](/docs/hooks-reference.html#conditionally-firing-an-effect) as the last argument to `useEffect`, `useMemo`, `useCallback`, or `useImperativeHandle`, it must include all values used inside that participate in the React data flow. That includes props, state, and anything derived from them. + +It is **only** safe to omit a function from the dependency list if nothing in it (or the functions called by it) references props, state, or values derived from them. This example has a bug: + +```js{5,12} +function ProductPage({ productId }) { + const [product, setProduct] = useState(null); + + async function fetchProduct() { + const response = await fetch('http://myapi/product' + productId); // Uses productId prop + const json = await response.json(); + setProduct(json); + } + + useEffect(() => { + fetchProduct(); + }, []); // 🔴 Invalid because `fetchProduct` uses `productId` + // ... +} +``` + +**The recommended fix is to move that function _inside_ of your effect**. That makes it easy to see which props or state your effect uses, and to ensure they're all declared: + +```js{5-10,13} +function ProductPage({ productId }) { + const [product, setProduct] = useState(null); + + useEffect(() => { + // By moving this function inside the effect, we can clearly see the values it uses. + async function fetchProduct() { + const response = await fetch('http://myapi/product' + productId); + const json = await response.json(); + setProduct(json); + } + + fetchProduct(); + }, [productId]); // ✅ Valid because our effect only uses productId + // ... +} +``` + +This also allows you to handle out-of-order responses with a local variable inside the effect: + +```js{2,6,8} + useEffect(() => { + let ignore = false; + async function fetchProduct() { + const response = await fetch('http://myapi/product/' + productId); + const json = await response.json(); + if (!ignore) setProduct(json); + } + return () => { ignore = true }; + }, [productId]); +``` + +We moved the function inside the effect so it doesn't need to be in its dependency list. + +>Tip +> +>Check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. + +**If for some reason you _can't_ move a function inside an effect, there are a few more options:** + +* **You can try moving that function outside of your component**. In that case, the function is guaranteed to not reference any props or state, and also doesn't need to be in the list of dependencies. +* If the function you're calling is a pure computation and is safe to call while rendering, you may **call it outside of the effect instead,** and make the effect depend on the returned value. +* As a last resort, you can **add a function to effect dependencies but _wrap its definition_** into the [`useCallback`](/docs/hooks-reference.html#usecallback) Hook. This ensures it doesn't change on every render unless *its own* dependencies also change: + +```js{2-5} +function ProductPage({ productId }) { + // ✅ Wrap with useCallback to avoid change on every render + const fetchProduct = useCallback(() => { + // ... Does something with productId ... + }, [productId]); // ✅ All useCallback dependencies are specified + + return ; +} + +function ProductDetails({ fetchProduct }) + useEffect(() => { + fetchProduct(); + }, [fetchProduct]); // ✅ All useEffect dependencies are specified + // ... +} +``` + +Note that in the above example we **need** to keep the function in the dependencies list. This ensures that a change in the `productId` prop of `ProductPage` automatically triggers a refetch in the `ProductDetails` component. + +### What can I do if my effect dependencies change too often? + +Sometimes, your effect may be using reading state that changes too often. You might be tempted to omit that state from a list of dependencies, but that usually leads to bugs: + +```js{6,9} +function Counter() { + const [count, setCount] = useState(0); + + useEffect(() => { + const id = setInterval(() => { + setCount(count + 1); // This effect depends on the `count` state + }, 1000); + return () => clearInterval(id); + }, []); // 🔴 Bug: `count` is not specified as a dependency + + return

{count}

; +} +``` + +Specifying `[count]` as a list of dependencies would fix the bug, but would cause the interval to be reset on every change. That may not be desirable. To fix this, we can use the [functional update form of `setState`](/docs/hooks-reference.html#functional-updates). It lets us specify *how* the state needs to change without referencing the *current* state: + +```js{6,9} +function Counter() { + const [count, setCount] = useState(0); + + useEffect(() => { + const id = setInterval(() => { + setCount(c => c + 1); // ✅ This doesn't depend on `count` variable outside + }, 1000); + return () => clearInterval(id); + }, []); // ✅ Our effect doesn't use any variables in the component scope + + return

{count}

; +} +``` + +(The identity of the `setCount` function is guaranteed to be stable so it's safe to omit.) + +In more complex cases (such as if one state depends on another state), try moving the state update logic outside the effect with the [`useReducer` Hook](/docs/hooks-reference.html#usereducer). [This article](https://adamrackis.dev/state-and-use-reducer/) offers an example of how you can do this. **The identity of the `dispatch` function from `useReducer` is always stable** — even if the reducer function is declared inside the component and reads its props. + +As a last resort, if you want to something like `this` in a class, you can [use a ref](/docs/hooks-faq.html#is-there-something-like-instance-variables) to hold a mutable variable. Then you can write and read to it. For example: + +```js{2-6,10-11,16} +function Example(props) { + // Keep latest props in a ref. + let latestProps = useRef(props); + useEffect(() => { + latestProps.current = props; + }); + + useEffect(() => { + function tick() { + // Read latest props at any time + console.log(latestProps.current); + } + + const id = setInterval(tick, 1000); + return () => clearInterval(id); + }, []); // This effect never re-runs +} +``` + +Only do this if you couldn't find a better alternative, as relying on mutation makes components less predictable. If there's a specific pattern that doesn't translate well, [file an issue](https://github.com/facebook/react/issues/new) with a runnable example code and we can try to help. + ### How do I implement `shouldComponentUpdate`? {#how-do-i-implement-shouldcomponentupdate} You can wrap a function component with `React.memo` to shallowly compare its props: @@ -430,7 +677,6 @@ It's not a Hook because it doesn't compose like Hooks do. `React.memo` is equiva `React.memo` doesn't compare state because there is no single state object to compare. But you can make children pure too, or even [optimize individual children with `useMemo`](/docs/hooks-faq.html#how-to-memoize-calculations). - ### How to memoize calculations? {#how-to-memoize-calculations} The [`useMemo`](/docs/hooks-reference.html#usememo) Hook lets you cache calculations between multiple renders by "remembering" the previous computation: diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index deeef54cf..4466bc83b 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -45,6 +45,10 @@ setState(newState); During subsequent re-renders, the first value returned by `useState` will always be the most recent state after applying updates. +>Note +> +>React guarantees that `setState` function identity is stable and won't change on re-renders. This is why it's safe to omit from the `useEffect` or `useCallback` dependency list. + #### Functional updates {#functional-updates} If the new state is computed using the previous state, you can pass a function to `setState`. The function will receive the previous value, and return an updated value. Here's an example of a counter component that uses both forms of `setState`: @@ -133,7 +137,7 @@ Although `useEffect` is deferred until after the browser has painted, it's guara #### Conditionally firing an effect {#conditionally-firing-an-effect} -The default behavior for effects is to fire the effect after every completed render. That way an effect is always recreated if one of its inputs changes. +The default behavior for effects is to fire the effect after every completed render. That way an effect is always recreated if one of its dependencies changes. However, this may be overkill in some cases, like the subscription example from the previous section. We don't need to create a new subscription on every update, only if the `source` props has changed. @@ -153,11 +157,18 @@ useEffect( Now the subscription will only be recreated when `props.source` changes. -Passing in an empty array `[]` of inputs tells React that your effect doesn't depend on any values from the component, so that effect would run only on mount and clean up on unmount; it won't run on updates. - -> Note +>Note +> +>If you use this optimization, make sure the array includes **all values from the component scope (such as props and state) that change over time and that are used by the effect**. Otherwise, your code will reference stale values from previous renders. Learn more about [how to deal with functions](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) and what to do when the [array values change too often](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often). +> +>If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array (`[]`) as a second argument. This tells React that your effect doesn't depend on *any* values from props or state, so it never needs to re-run. This isn't handled as a special case -- it follows directly from how the dependencies array always works. > -> The array of inputs is not passed as arguments to the effect function. Conceptually, though, that's what they represent: every value referenced inside the effect function should also appear in the inputs array. In the future, a sufficiently advanced compiler could create this array automatically. +>If you pass an empty array (`[]`), the props and state as inside the effect will always have their initial values. While passing `[]` as the second argument is closer to the familiar `componentDidMount` and `componentWillUnmount` mental model, there are usually [better](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) [solutions](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often) to avoid re-running effects too often. Also, don't forget that React defers running `useEffect` until after the browser has painted, so doing extra work is less of a problem. +> +> +>We recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation) package. It warns when dependencies are specified incorrectly and suggests a fix. + +The array of dependencies is not passed as arguments to the effect function. Conceptually, though, that's what they represent: every value referenced inside the effect function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically. ### `useContext` {#usecontext} @@ -211,6 +222,10 @@ function Counter({initialState}) { } ``` +>Note +> +>React guarantees that `dispatch` function identity is stable and won't change on re-renders. This is why it's safe to omit from the `useEffect` or `useCallback` dependency list. + #### Specifying the initial state {#specifying-the-initial-state} 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: @@ -283,13 +298,15 @@ const memoizedCallback = useCallback( Returns a [memoized](https://en.wikipedia.org/wiki/Memoization) callback. -Pass an inline callback and an array of inputs. `useCallback` will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. `shouldComponentUpdate`). +Pass an inline callback and an array of dependencies. `useCallback` will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. `shouldComponentUpdate`). -`useCallback(fn, inputs)` is equivalent to `useMemo(() => fn, inputs)`. +`useCallback(fn, deps)` is equivalent to `useMemo(() => fn, deps)`. > Note > -> The array of inputs is not passed as arguments to the callback. Conceptually, though, that's what they represent: every value referenced inside the callback should also appear in the inputs array. In the future, a sufficiently advanced compiler could create this array automatically. +> The array of dependencies is not passed as arguments to the callback. Conceptually, though, that's what they represent: every value referenced inside the callback should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically. +> +> We recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation) package. It warns when dependencies are specified incorrectly and suggests a fix. ### `useMemo` {#usememo} @@ -299,7 +316,7 @@ const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); Returns a [memoized](https://en.wikipedia.org/wiki/Memoization) value. -Pass a "create" function and an array of inputs. `useMemo` will only recompute the memoized value when one of the inputs has changed. This optimization helps to avoid expensive calculations on every render. +Pass a "create" function and an array of dependencies. `useMemo` will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render. Remember that the function passed to `useMemo` runs during rendering. Don't do anything there that you wouldn't normally do while rendering. For example, side effects belong in `useEffect`, not `useMemo`. @@ -309,7 +326,9 @@ If no array is provided, a new value will be computed whenever a new function in > Note > -> The array of inputs is not passed as arguments to the function. Conceptually, though, that's what they represent: every value referenced inside the function should also appear in the inputs array. In the future, a sufficiently advanced compiler could create this array automatically. +> The array of dependencies is not passed as arguments to the function. Conceptually, though, that's what they represent: every value referenced inside the function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically. +> +> We recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation) package. It warns when dependencies are specified incorrectly and suggests a fix. ### `useRef` {#useref} @@ -342,7 +361,7 @@ Note that `useRef()` is useful for more than the `ref` attribute. It's [handy fo ### `useImperativeHandle` {#useimperativehandle} ```js -useImperativeHandle(ref, createHandle, [inputs]) +useImperativeHandle(ref, createHandle, [deps]) ``` `useImperativeHandle` customizes the instance value that is exposed to parent components when using `ref`. As always, imperative code using refs should be avoided in most cases. `useImperativeHandle` should be used with `forwardRef`: diff --git a/content/docs/hooks-rules.md b/content/docs/hooks-rules.md index 698d1c741..8c332578c 100644 --- a/content/docs/hooks-rules.md +++ b/content/docs/hooks-rules.md @@ -40,7 +40,8 @@ npm install eslint-plugin-react-hooks ], "rules": { // ... - "react-hooks/rules-of-hooks": "error" + "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks + "react-hooks/exhaustive-deps": "warning" // Checks effect dependencies } } ``` From 83faa76713205d2c669005d6d51d29ee65079cf7 Mon Sep 17 00:00:00 2001 From: Victoria Quirante Date: Wed, 13 Mar 2019 16:28:05 +0100 Subject: [PATCH 23/30] Add React Alicante 2019 (#1819) --- content/community/conferences.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/community/conferences.md b/content/community/conferences.md index 89ed871d0..e138b119a 100644 --- a/content/community/conferences.md +++ b/content/community/conferences.md @@ -76,6 +76,11 @@ September 26-28, 2019 in Goa, India [Website](https://www.reactindia.io/) - [Twitter](https://twitter.com/react_india) - [Facebook](https://www.facebook.com/ReactJSIndia) +### React Alicante 2019 {#react-alicante-2019} +September 26-28, 2019 in Alicante, Spain + +[Website](http://reactalicante.es/) - [Twitter](https://twitter.com/reactalicante) - [Facebook](https://www.facebook.com/ReactAlicante) + ## Past Conferences {#past-conferences} ### React.js Conf 2015 {#reactjs-conf-2015} From 110a318d1efc7d2c60644bd160dcac359b8778fb Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 13 Mar 2019 15:38:51 +0000 Subject: [PATCH 24/30] Link to a data fetching demo --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 6145b968d..1f36f5f17 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -210,7 +210,7 @@ There are a few more heuristics, and they might change over time as we fine-tune ### How can I do data fetching with Hooks? -Check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. +Here is a [small demo](https://codesandbox.io/s/pwm32zx7z7) to get you started. To learn more, check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. ### Is there something like instance variables? {#is-there-something-like-instance-variables} From 474de38b2c1e9dc8d9e6cc30b1cb0e8ff4ae3628 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 13 Mar 2019 15:42:01 +0000 Subject: [PATCH 25/30] Use another example --- content/docs/hooks-faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 1f36f5f17..df6d9f7c3 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -210,7 +210,7 @@ There are a few more heuristics, and they might change over time as we fine-tune ### How can I do data fetching with Hooks? -Here is a [small demo](https://codesandbox.io/s/pwm32zx7z7) to get you started. To learn more, check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. +Here is a [small demo](https://codesandbox.io/s/jvvkoo8pq3) to get you started. To learn more, check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. ### Is there something like instance variables? {#is-there-something-like-instance-variables} @@ -571,7 +571,7 @@ We moved the function inside the effect so it doesn't need to be in its dependen >Tip > ->Check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. +>Check out [this small demo](https://codesandbox.io/s/jvvkoo8pq3) and [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. **If for some reason you _can't_ move a function inside an effect, there are a few more options:** From 877b1897588c7c4640ecf1f6841adfe3986c44b8 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 13 Mar 2019 15:46:05 +0000 Subject: [PATCH 26/30] Fix wording --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index df6d9f7c3..0540031ba 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -210,7 +210,7 @@ There are a few more heuristics, and they might change over time as we fine-tune ### How can I do data fetching with Hooks? -Here is a [small demo](https://codesandbox.io/s/jvvkoo8pq3) to get you started. To learn more, check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. +Here is a [small demo](https://codesandbox.io/s/jvvkoo8pq3) to get you started. To learn more, check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) about data fetching with Hooks. ### Is there something like instance variables? {#is-there-something-like-instance-variables} From 352c3ff01f437de2441533313bb1feb2c3f87414 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 13 Mar 2019 18:24:10 +0000 Subject: [PATCH 27/30] Fix example --- content/docs/hooks-faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 0540031ba..9016fa7f4 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -467,7 +467,7 @@ Yes. See [conditionally firing an effect](/docs/hooks-reference.html#conditional Generally speaking, no. ```js{3,8} -function Example() { +function Example({ someProp }) { function doSomething() { console.log(someProp); } @@ -481,7 +481,7 @@ function Example() { It's difficult to remember which props or state are used by functions outside of the effect. This is why **usually you'll want to declare functions needed by an effect *inside* of it.** Then it's easy to see what values from the component scope that effect depends on: ```js{4,8} -function Example() { +function Example({ someProp }) { useEffect(() => { function doSomething() { console.log(someProp); From 3e489fc2f9a028d570ccfdd74ddbc93faea27d32 Mon Sep 17 00:00:00 2001 From: Manuel Bieh Date: Thu, 14 Mar 2019 01:09:09 +0100 Subject: [PATCH 28/30] Fixing incorrect value for eslint rule (#1824) The name for the "warning" level in ESLint is `warn` not `warning` (https://eslint.org/docs/user-guide/configuring#configuring-rules) --- content/docs/hooks-rules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-rules.md b/content/docs/hooks-rules.md index 8c332578c..dbac9cffd 100644 --- a/content/docs/hooks-rules.md +++ b/content/docs/hooks-rules.md @@ -41,7 +41,7 @@ npm install eslint-plugin-react-hooks "rules": { // ... "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks - "react-hooks/exhaustive-deps": "warning" // Checks effect dependencies + "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies } } ``` From 40bbbd5b102cd33bdee85fcc4bd209dc06585975 Mon Sep 17 00:00:00 2001 From: Dimitar Nestorov Date: Thu, 14 Mar 2019 16:49:11 +0200 Subject: [PATCH 29/30] Updating useMemo docs (#1796) https://codesandbox.io/s/4x68k8nrw --- content/docs/hooks-reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index 4466bc83b..4daf0f191 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -320,7 +320,7 @@ Pass a "create" function and an array of dependencies. `useMemo` will only recom Remember that the function passed to `useMemo` runs during rendering. Don't do anything there that you wouldn't normally do while rendering. For example, side effects belong in `useEffect`, not `useMemo`. -If no array is provided, a new value will be computed whenever a new function instance is passed as the first argument. (With an inline function, on every render.) +If no array is provided, a new value will be computed on every render. **You may rely on `useMemo` as a performance optimization, not as a semantic guarantee.** In the future, React may choose to "forget" some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without `useMemo` — and then add it to optimize performance. From 1fe2e0ae29b2fe8a8a09ab10048bb9fe284ff568 Mon Sep 17 00:00:00 2001 From: Nelson Reitz Date: Fri, 15 Mar 2019 15:04:19 +0100 Subject: [PATCH 30/30] Fix overflowing headers on small screens (#1830) --- src/theme.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/theme.js b/src/theme.js index 9f440d56d..a4d445206 100644 --- a/src/theme.js +++ b/src/theme.js @@ -89,6 +89,11 @@ const fonts = { lineHeight: '65px', fontWeight: 700, + [media.lessThan('small')]: { + overflowWrap: 'break-word', + wordBreak: 'break-word', + }, + [media.lessThan('medium')]: { fontSize: 40, lineHeight: '45px',