Browse Source

[Beta] Port some warning pages

main
Dan Abramov 2 years ago
parent
commit
dd213e4efe
  1. 11
      beta/src/content/warnings/invalid-aria-prop.md
  2. 158
      beta/src/content/warnings/invalid-hook-call-warning.md
  3. 7
      beta/src/content/warnings/special-props.md
  4. 61
      beta/src/content/warnings/unknown-prop.md

11
beta/src/content/warnings/invalid-aria-prop.md

@ -0,0 +1,11 @@
---
title: Invalid ARIA Prop Warning
---
This warning will fire if you attempt to render a DOM element with an `aria-*` prop that does not exist in the Web Accessibility Initiative (WAI) Accessible Rich Internet Application (ARIA) [specification](https://www.w3.org/TR/wai-aria-1.1/#states_and_properties).
1. If you feel that you are using a valid prop, check the spelling carefully. `aria-labelledby` and `aria-activedescendant` are often misspelled.
2. If you wrote `aria-role`, you may have meant `role`.
3. Otherwise, if you're on the latest version of React DOM and verified that you're using a valid property name listed in the ARIA specification, please [report a bug](https://github.com/facebook/react/issues/new/choose).

158
beta/src/content/warnings/invalid-hook-call-warning.md

@ -0,0 +1,158 @@
---
title: Rules of Hooks
---
You are probably here because you got the following error message:
<ConsoleBlock level="error">
Hooks can only be called inside the body of a function component.
</ConsoleBlock>
There are three common reasons you might be seeing it:
1. You might be **breaking the Rules of Hooks**.
2. You might have **mismatching versions** of React and React DOM.
3. You might have **more than one copy of React** in the same app.
Let's look at each of these cases.
## Breaking Rules of Hooks {/*breaking-rules-of-hooks*/}
Functions whose names start with `use` are called [*Hooks*](/reference/react) in React.
**Don’t call Hooks inside loops, conditions, or nested functions.** Instead, always use Hooks at the top level of your React function, before any early returns. You can only call Hooks while React is rendering a function component:
* ✅ Call them at the top level in the body of a [function component](/learn/your-first-component).
* ✅ Call them at the top level in the body of a [custom Hook](/learn/reusing-logic-with-custom-hooks).
```js{2-3,8-9}
function Counter() {
// ✅ Good: top-level in a function component
const [count, setCount] = useState(0);
// ...
}
function useWindowWidth() {
// ✅ Good: top-level in a custom Hook
const [width, setWidth] = useState(window.innerWidth);
// ...
}
```
It’s **not** supported to call Hooks (functions starting with `use`) in any other cases, for example:
* 🔴 Do not call Hooks inside conditions or loops.
* 🔴 Do not call Hooks after a conditional `return` statement.
* 🔴 Do not call Hooks in event handlers.
* 🔴 Do not call Hooks in class components.
* 🔴 Do not call Hooks inside functions passed to `useMemo`, `useReducer`, or `useEffect`.
If you break these rules, you might see this error.
```js{3-4,11-12,20-21}
function Bad({ cond }) {
if (cond) {
// 🔴 Bad: inside a condition (to fix, move it outside!)
const theme = useContext(ThemeContext);
}
// ...
}
function Bad() {
for (let i = 0; i < 10; i++) {
// 🔴 Bad: inside a loop (to fix, move it outside!)
const theme = useContext(ThemeContext);
}
// ...
}
function Bad({ cond }) {
if (cond) {
return;
}
// 🔴 Bad: after a conditional return (to fix, move it before the return!)
const theme = useContext(ThemeContext);
// ...
}
function Bad() {
function handleClick() {
// 🔴 Bad: inside an event handler (to fix, move it outside!)
const theme = useContext(ThemeContext);
}
// ...
}
function Bad() {
const style = useMemo(() => {
// 🔴 Bad: inside useMemo (to fix, move it outside!)
const theme = useContext(ThemeContext);
return createStyle(theme);
});
// ...
}
class Bad extends React.Component {
render() {
// 🔴 Bad: inside a class component (to fix, write a function component instead of a class!)
useEffect(() => {})
// ...
}
}
```
You can use the [`eslint-plugin-react-hooks` plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) to catch these mistakes.
<Note>
[Custom Hooks](/learn/reusing-logic-with-custom-hooks) *may* call other Hooks (that's their whole purpose). This works because custom Hooks are also supposed to only be called while a function component is rendering.
</Note>
## Mismatching Versions of React and React DOM {/*mismatching-versions-of-react-and-react-dom*/}
You might be using a version of `react-dom` (< 16.8.0) or `react-native` (< 0.59) that doesn't yet support Hooks. You can run `npm ls react-dom` or `npm ls react-native` in your application folder to check which version you're using. If you find more than one of them, this might also create problems (more on that below).
## Duplicate React {/*duplicate-react*/}
In order for Hooks to work, the `react` import from your application code needs to resolve to the same module as the `react` import from inside the `react-dom` package.
If these `react` imports resolve to two different exports objects, you will see this warning. This may happen if you **accidentally end up with two copies** of the `react` package.
If you use Node for package management, you can run this check in your project folder:
<TerminalBlock>
npm ls react
</TerminalBlock>
If you see more than one React, you'll need to figure out why this happens and fix your dependency tree. For example, maybe a library you're using incorrectly specifies `react` as a dependency (rather than a peer dependency). Until that library is fixed, [Yarn resolutions](https://yarnpkg.com/lang/en/docs/selective-version-resolutions/) is one possible workaround.
You can also try to debug this problem by adding some logs and restarting your development server:
```js
// Add this in node_modules/react-dom/index.js
window.React1 = require('react');
// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);
```
If it prints `false` then you might have two Reacts and need to figure out why that happened. [This issue](https://github.com/facebook/react/issues/13991) includes some common reasons encountered by the community.
This problem can also come up when you use `npm link` or an equivalent. In that case, your bundler might "see" two Reacts — one in application folder and one in your library folder. Assuming `myapp` and `mylib` are sibling folders, one possible fix is to run `npm link ../myapp/node_modules/react` from `mylib`. This should make the library use the application's React copy.
<Note>
In general, React supports using multiple independent copies on one page (for example, if an app and a third-party widget both use it). It only breaks if `require('react')` resolves differently between the component and the `react-dom` copy it was rendered with.
</Note>
## Other Causes {/*other-causes*/}
If none of this worked, please comment in [this issue](https://github.com/facebook/react/issues/13991) and we'll try to help. Try to create a small reproducing example — you might discover the problem as you're doing it.

7
beta/src/content/warnings/special-props.md

@ -0,0 +1,7 @@
---
title: Special Props Warning
---
Most props on a JSX element are passed on to the component, however, there are two special props (`ref` and `key`) which are used by React, and are thus not forwarded to the component.
For instance, you can't read `props.key` from a component. If you need to access the same value within the child component, you should pass it as a different prop (ex: `<ListItemWrapper key={result.id} id={result.id} />` and read `props.id`). While this may seem redundant, it's important to separate app logic from hints to React.

61
beta/src/content/warnings/unknown-prop.md

@ -0,0 +1,61 @@
---
title: Unknown Prop Warning
---
The unknown-prop warning will fire if you attempt to render a DOM element with a prop that is not recognized by React as a legal DOM attribute/property. You should ensure that your DOM elements do not have spurious props floating around.
There are a couple of likely reasons this warning could be appearing:
1. Are you using `{...props}` or `cloneElement(element, props)`? When copying props to a child component, you should ensure that you are not accidentally forwarding props that were intended only for the parent component. See common fixes for this problem below.
2. You are using a non-standard DOM attribute on a native DOM node, perhaps to represent custom data. If you are trying to attach custom data to a standard DOM element, consider using a custom data attribute as described [on MDN](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes).
3. React does not yet recognize the attribute you specified. This will likely be fixed in a future version of React. React will allow you to pass it without a warning if you write the attribute name lowercase.
4. You are using a React component without an upper case, for example `<myButton />`. React interprets it as a DOM tag because React JSX transform uses the upper vs. lower case convention to distinguish between user-defined components and DOM tags. For your own React components, use PascalCase. For example, write `<MyButton />` instead of `<myButton />`.
---
If you get this warning because you pass props like `{...props}`, your parent component needs to "consume" any prop that is intended for the parent component and not intended for the child component. Example:
**Bad:** Unexpected `layout` prop is forwarded to the `div` tag.
```js
function MyDiv(props) {
if (props.layout === 'horizontal') {
// BAD! Because you know for sure "layout" is not a prop that <div> understands.
return <div {...props} style={getHorizontalStyle()} />
} else {
// BAD! Because you know for sure "layout" is not a prop that <div> understands.
return <div {...props} style={getVerticalStyle()} />
}
}
```
**Good:** The spread syntax can be used to pull variables off props, and put the remaining props into a variable.
```js
function MyDiv(props) {
const { layout, ...rest } = props
if (layout === 'horizontal') {
return <div {...rest} style={getHorizontalStyle()} />
} else {
return <div {...rest} style={getVerticalStyle()} />
}
}
```
**Good:** You can also assign the props to a new object and delete the keys that you're using from the new object. Be sure not to delete the props from the original `this.props` object, since that object should be considered immutable.
```js
function MyDiv(props) {
const divProps = Object.assign({}, props);
delete divProps.layout;
if (props.layout === 'horizontal') {
return <div {...divProps} style={getHorizontalStyle()} />
} else {
return <div {...divProps} style={getVerticalStyle()} />
}
}
```
Loading…
Cancel
Save