Browse Source

[Beta] Remove inline useEvent impl (#5101)

main
dan 3 years ago
committed by GitHub
parent
commit
d56aec2dd1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      beta/src/content/learn/escape-hatches.md
  2. 124
      beta/src/content/learn/removing-effect-dependencies.md
  3. 137
      beta/src/content/learn/reusing-logic-with-custom-hooks.md
  4. 269
      beta/src/content/learn/separating-events-from-effects.md

25
beta/src/content/learn/escape-hatches.md

@ -455,8 +455,8 @@ This is not ideal. You want to re-connect to the chat only if the `roomId` has c
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -471,7 +471,7 @@ This is not ideal. You want to re-connect to the chat only if the `roomId` has c
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
import { createConnection, sendMessage } from './chat.js';
import { showNotification } from './notifications.js';
@ -575,25 +575,6 @@ export function showNotification(message, theme) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label { display: block; margin-top: 10px; }
```

124
beta/src/content/learn/removing-effect-dependencies.md

@ -1253,10 +1253,26 @@ Is there a line of code inside the Effect that should not be reactive? How can y
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useState, useEffect, useRef } from 'react';
import { experimental_useEvent as useEvent } from 'react';
import { FadeInAnimation } from './animation.js';
import { useEvent } from './useEvent.js';
function Welcome({ duration }) {
const ref = useRef(null);
@ -1351,25 +1367,6 @@ export class FadeInAnimation {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label, button { display: block; margin-bottom: 20px; }
html, body { min-height: 300px; }
@ -1383,10 +1380,26 @@ Your Effect needs to read the latest value of `duration`, but you don't want it
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useState, useEffect, useRef } from 'react';
import { FadeInAnimation } from './animation.js';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
function Welcome({ duration }) {
const ref = useRef(null);
@ -1479,25 +1492,6 @@ export class FadeInAnimation {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label, button { display: block; margin-bottom: 20px; }
html, body { min-height: 300px; }
@ -1825,8 +1819,8 @@ Another of these functions only exists to pass some state to an imported API met
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -1907,7 +1901,7 @@ export default function App() {
```js ChatRoom.js active
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export default function ChatRoom({ roomId, createConnection, onMessage }) {
useEffect(() => {
@ -2023,25 +2017,6 @@ export function showNotification(message, theme) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label, button { display: block; margin-bottom: 5px; }
```
@ -2139,8 +2114,8 @@ As a result, the chat re-connects only when something meaningful (`roomId` or `i
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -2208,7 +2183,7 @@ export default function App() {
```js ChatRoom.js active
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
import {
createEncryptedConnection,
createUnencryptedConnection,
@ -2342,25 +2317,6 @@ export function showNotification(message, theme) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label, button { display: block; margin-bottom: 5px; }
```

137
beta/src/content/learn/reusing-logic-with-custom-hooks.md

@ -985,7 +985,7 @@ export default function ChatRoom({ roomId }) {
```js useChatRoom.js
import { useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
import { createConnection } from './chat.js';
export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
@ -1006,25 +1006,6 @@ export function useChatRoom({ serverUrl, roomId, onReceiveMessage }) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```js chat.js
export function createConnection({ serverUrl, roomId }) {
// A real implementation would actually connect to the server
@ -1089,8 +1070,8 @@ export function showNotification(message, theme = 'dark') {
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -1660,7 +1641,7 @@ export default function App() {
```js useFadeIn.js active
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export function useFadeIn(ref, duration) {
const [isRunning, setIsRunning] = useState(true);
@ -1696,25 +1677,6 @@ function useAnimationLoop(isRunning, drawFrame) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label, button { display: block; margin-bottom: 20px; }
html, body { min-height: 300px; }
@ -1728,6 +1690,22 @@ html, body { min-height: 300px; }
}
```
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
</Sandpack>
However, you didn't *have to* do that. As with regular functions, ultimately you decide where to draw the boundaries between different parts of your code. For example, you could also take a very different approach. Instead of keeping the logic in the Effect, you could move most of the imperative logic inside a JavaScript [class:](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
@ -2202,6 +2180,22 @@ It looks like your `useInterval` Hook accepts an event listener as an argument.
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useCounter } from './useCounter.js';
import { useInterval } from './useInterval.js';
@ -2233,7 +2227,7 @@ export function useCounter(delay) {
```js useInterval.js
import { useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export function useInterval(onTick, delay) {
useEffect(() => {
@ -2245,25 +2239,6 @@ export function useInterval(onTick, delay) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
</Sandpack>
<Solution>
@ -2276,6 +2251,23 @@ With this change, both intervals work as expected and don't interfere with each
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useCounter } from './useCounter.js';
import { useInterval } from './useInterval.js';
@ -2307,7 +2299,7 @@ export function useCounter(delay) {
```js useInterval.js active
import { useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export function useInterval(callback, delay) {
const onTick = useEvent(callback);
@ -2318,25 +2310,6 @@ export function useInterval(callback, delay) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
</Sandpack>
</Solution>

269
beta/src/content/learn/separating-events-from-effects.md

@ -448,8 +448,8 @@ Verify that the new behavior works as you would expect:
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -464,7 +464,7 @@ Verify that the new behavior works as you would expect:
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
import { createConnection, sendMessage } from './chat.js';
import { showNotification } from './notifications.js';
@ -568,25 +568,6 @@ export function showNotification(message, theme) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label { display: block; margin-top: 10px; }
```
@ -817,7 +798,7 @@ With `useEvent`, there is no need to "lie" to the linter, and the code works as
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export default function App() {
const [position, setPosition] = useState({ x: 0, y: 0 });
@ -861,25 +842,6 @@ export default function App() {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
body {
height: 200px;
@ -1106,9 +1068,25 @@ It seems like the Effect which sets up the timer "reacts" to the `increment` val
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export default function Timer() {
const [count, setCount] = useState(0);
@ -1145,25 +1123,6 @@ export default function Timer() {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
button { margin: 10px; }
```
@ -1178,9 +1137,25 @@ To solve the issue, extract an `onTick` Event function from the Effect:
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export default function Timer() {
const [count, setCount] = useState(0);
@ -1222,25 +1197,6 @@ export default function Timer() {
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
button { margin: 10px; }
```
@ -1263,9 +1219,25 @@ Code inside Event functions is not reactive. Are there cases in which you would
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export default function Timer() {
const [count, setCount] = useState(0);
@ -1322,25 +1294,6 @@ export default function Timer() {
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
button { margin: 10px; }
```
@ -1353,9 +1306,25 @@ The problem with the above example is that it extracted an Event function called
<Sandpack>
```json package.json hidden
{
"dependencies": {
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
```
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
export default function Timer() {
const [count, setCount] = useState(0);
@ -1407,25 +1376,6 @@ export default function Timer() {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
button { margin: 10px; }
```
@ -1455,8 +1405,8 @@ Your Effect knows which room it connected to. Is there any information that you
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -1471,7 +1421,7 @@ Your Effect knows which room it connected to. Is there any information that you
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
import { createConnection, sendMessage } from './chat.js';
import { showNotification } from './notifications.js';
@ -1577,25 +1527,6 @@ export function showNotification(message, theme) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label { display: block; margin-top: 10px; }
```
@ -1615,8 +1546,8 @@ To fix the issue, instead of reading the *latest* `roomId` inside the Event func
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -1631,7 +1562,7 @@ To fix the issue, instead of reading the *latest* `roomId` inside the Event func
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
import { createConnection, sendMessage } from './chat.js';
import { showNotification } from './notifications.js';
@ -1737,25 +1668,6 @@ export function showNotification(message, theme) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label { display: block; margin-top: 10px; }
```
@ -1771,8 +1683,8 @@ To solve the additional challenge, save the notification timeout ID and clear it
```json package.json hidden
{
"dependencies": {
"react": "latest",
"react-dom": "latest",
"react": "experimental",
"react-dom": "experimental",
"react-scripts": "latest",
"toastify-js": "1.12.0"
},
@ -1787,7 +1699,7 @@ To solve the additional challenge, save the notification timeout ID and clear it
```js
import { useState, useEffect } from 'react';
import { useEvent } from './useEvent.js';
import { experimental_useEvent as useEvent } from 'react';
import { createConnection, sendMessage } from './chat.js';
import { showNotification } from './notifications.js';
@ -1899,25 +1811,6 @@ export function showNotification(message, theme) {
}
```
```js useEvent.js
import { useRef, useInsertionEffect, useCallback } from 'react';
// The useEvent API has not yet been added to React,
// so this is a temporary shim to make this sandbox work.
// You're not expected to write code like this yourself.
export function useEvent(fn) {
const ref = useRef(null);
useInsertionEffect(() => {
ref.current = fn;
}, [fn]);
return useCallback((...args) => {
const f = ref.current;
return f(...args);
}, []);
}
```
```css
label { display: block; margin-top: 10px; }
```

Loading…
Cancel
Save