Ric*_*ler 14 javascript reactjs react-hooks
React文档明确指出,有条件地调用钩子是行不通的。从最初的React hooks演示文稿开始,原因是因为React使用您调用hook的顺序来注入正确的值。
我理解这一点,但是现在我的问题是,从带有钩子的函数组件中尽早返回是否可以?
所以允许这样的事情:
import React from 'react';
import { useRouter, Redirect } from 'react-router';
import { useSelector } from 'react-redux';
export default function Component() {
const { match } = useRouter({ path: '/:some/:thing' });
if (!match) return <Redirect to="/" />;
const { some, thing } = match.params;
const state = useSelector(stateSelector(some, thing));
return <Blah {...state} />;
}
Run Code Online (Sandbox Code Playgroud)
从技术上讲,该useSelector挂钩是有条件地调用的,但是在渲染之间它们的调用顺序不会改变(即使有可能会调用更少的挂钩)。
如果不允许这样做,您能否解释为什么不允许这样做,并提供通用的替代方法来尽早返回带有挂钩的函数组件?
Rya*_*ell 10
React does not allow you to do an early return prior to other hooks. If a component executes fewer hooks than a previous render, you will get the following error:
Invariant Violation: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
React can't tell the difference between an early return and a conditional hook call. For instance, if you have 3 calls to useState and you sometimes return after the second one, React can't tell whether you returned after the second useState call or if you put a condition around the first or second useState call, so it can't reliably know whether or not it is returning the correct state for the two useState calls that did occur.
Here's an example that you can use to see this error in action (click the "Increment State 1" button twice to get the error):
import React from "react";
import ReactDOM from "react-dom";
function App() {
const [state1, setState1] = React.useState(1);
if (state1 === 3) {
return <div>State 1 is 3</div>;
}
const [state2, setState2] = React.useState(2);
return (
<div className="App">
<div>State 1: {state1}</div>
<div>State 2: {state2}</div>
<button onClick={() => setState1(state1 + 1)}>Increment State 1</button>
<button onClick={() => setState2(state2 + 1)}>Increment State 2</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)
The alternative approach I would recommend is to separate the portion after the early return into its own component. Anything needed by the portion after the early return gets passed to the new component as props.
In the case of my example, it could look like the following:
import React from "react";
import ReactDOM from "react-dom";
const AfterEarlyReturn = ({ state1, setState1 }) => {
const [state2, setState2] = React.useState(2);
return (
<div className="App">
<div>State 1: {state1}</div>
<div>State 2: {state2}</div>
<button onClick={() => setState1(state1 + 1)}>Increment State 1</button>
<button onClick={() => setState2(state2 + 1)}>Increment State 2</button>
</div>
);
};
function App() {
const [state1, setState1] = React.useState(1);
if (state1 === 3) {
return <div>State 1 is 3</div>;
}
return <AfterEarlyReturn state1={state1} setState1={setState1} />;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1759 次 |
| 最近记录: |