我在读《新概念》。我遇到了一条规则,上面说不要在条件内调用React hook
。在这里,他们提供了解释链接。
function Form() {
// 1. Use the name state variable
const [name, setName] = useState('Mary');
// 2. Use an effect for persisting the form
useEffect(function persistForm() {
localStorage.setItem('formData', name);
});
// 3. Use the surname state variable
const [surname, setSurname] = useState('Poppins');
// 4. Use an effect for updating the title
useEffect(function updateTitle() {
document.title = name + ' ' + surname;
});
// ...
}
我明白他们想说什么,但我不能得到确切的原因,比如为什么我不能在if-else块中使用useffect?
还有一种说法
那么React如何知道哪个状态对应于哪个useState调用呢?
useState每次都是不同的调用,每次都可以返回新的“[state,setState]”,所以这里有什么困难知道谁调用了哪个useState?
从React文档的回答中,它提到钩子存储在的“内存单元”
中,并按顺序呈现(“将指针移动到下一个”
)
每个组件都有一个内部“存储单元”列表。它们只是JavaScript对象,我们可以在其中放置一些数据。当调用像useState()这样的钩子时,它会读取当前单元格(或在第一次渲染时对其进行初始化),然后将指针移动到下一个单元格。这就是多个useState()调用每个获取独立本地状态的方式。
与您提供的链接的下面部分相匹配,其中有更多的解释
//第一次渲染//------------
Mary)//1.用'玛丽'初始化名称状态变量
useffect(persistForm)//2。添加用于持久化表单的效果
useState('Poppins')//3。使用“Poppins”初始化姓氏状态变量
useffect(updateTitle)//4。添加用于更新标题的效果
//------//第二次渲染//-------------
useState('Mary')//1。读取名称状态变量(忽略参数)
USEPERP(持久形式)//2.替换持久化窗体的效果
useState('Poppins')//3。读取姓氏状态变量(忽略参数)
useffect(updateTitle)//4。替换用于更新标题的效果
在第二个渲染部分中,文档说,读取。。。变量
意味着当第二次调用useState
时,它不会生成新的[state,setState],而是进入的“内存单元”
读取状态值并返回,然后我们通过常量[state,setState]=useEffect()将其分配给新数组。这就是为什么React可以保证每次重新渲染时不会更改
setState
React保证setState函数标识是稳定的,并且在重新渲染时不会更改。这就是为什么从useEffect或useCallback依赖项列表中省略是安全的。
这不是关于谁调用了哪个钩子useXXXX
(即useState
,useffect
,等等)。它是关于钩子如何在内部实现以及如何与每个组件关联。还有许多其他问题需要解决,这取决于钩子的调用顺序。
从docs Hooks常见问题部分
React如何将钩子调用与组件相关联?
每个组件都有一个内部“存储单元”列表。它们只是JavaScript对象,我们可以在其中放置一些数据。当调用像useState()这样的钩子时,它会读取当前单元格(或在第一次渲染时对其进行初始化),然后将指针移动到下一个单元格。这就是多个useState()调用每个获取独立本地状态的方式。
内部钩子的实现类似于一个队列,其中每个钩子代表一个引用下一个节点的节点。内部结构可能与此类似,
{
memoizedState: 'a',
next: {
memoizedState: 'b',
next: null
}
}
以调用useState
4次来获得4个状态变量为例。对于每个钩子调用,如果值尚未初始化(即在第一次渲染时),它将初始化从内存单元读取的值,然后在内部移动到下一个钩子。
// 4 independent local state variables with their own "memory cell"
// nothing is called conditionally so the call order remains the same
// across renders
useState(1) // 1st call
useState(2) // 2nd call
useState(3) // 3rd call
useState(4) // 4th call
useState(1)
if (condition) { // if condition false hook call will be skipped
useState(2)
}
useState(3)
useState(4)
现在,当您有条件地调用钩子时,如果条件是false
,钩子调用将被跳过。这意味着每个后续的钩子调用将在调用顺序中移位1,导致无法读取状态值或替换效果或更难检测的错误。
所以一般来说,有条件地调用任何钩子都不是一个好主意。只在顶层调用钩子(而不是内部条件、嵌套函数或循环),这将有助于对多个钩子调用保持钩子的状态作出反应。
基本上,钩子依赖于调用索引。React不知道给定的useState()
返回了什么,因为它是前一个渲染的状态,但是它知道该组件对useState()
的第一次调用返回了一个[1,2]
作为它的值,第二次调用调用返回false
。现在,如果唯一的反应知道的是给定的调用索引的给定回报,你认为会发生什么,如果我可以写这样的组件:
const [a, setA] = React.useState([1,2,3]);
let c;
if(a === [3,2,1]){
c = React.useState('X');
}
const [b, setB] = React.useState(false);
React.useEffect(() => setA([3,2,1]), []);
现在,react从第一个渲染中知道第一个调用返回[1,2,3],第二个调用返回false。然后效果会重新渲染组件,现在它不是第一个渲染,因此第一个调用将返回状态[3,2,1]
,因为它已更新,第二个调用(一个c=…
)将返回false,但react看到第三个调用,它应该返回什么?
从react的角度来看,这毫无意义,从您的角度来看,这可能会导致大量的bug和问题。
当然,我的基本解释和React都不多,这就是为什么有消息来源,React工作人员之一丹·阿布拉莫夫在他的博客上有一篇很长很详细的文章,你可以在这里找到。他还发布了很多关于react如何在幕后工作的其他内容,值得一读。
我是反应的初学者。我试图将我的数据库的值从一个文件发送到另一个使用反应挂钩,并得到以下错误有人能帮我吗? 第5:41行:不能在顶层调用React钩子“useState”。必须在React函数组件或自定义React钩子函数React钩子/钩子规则代码中调用React钩子:
问题内容: 我正在尝试与大学的MySQL数据库建立连接,但该连接已挂起。 此调用:打印(在我最终杀死它之后): 我刚刚从下载的MySQL连接器/ J 这里。我不确定这是否是问题的一部分。我非常准确地遵循了指示。 我也可以像这样在命令行上连接到mysql: 可能的问题: 我写的Java代码 我如何安装MySQL Connector / J 某种网络问题阻止了连接 问题: 我应该怎么解决这个问题?为什
我在React hook中遇到了一些非常奇怪的行为。在下面的代码中(https://codesandbox.io/s/purple-bush-nb5uy?file=/src/index.js): 单击时,我们在控制台中获得以下序列: 我希望: 因为我认为如果React找到setter并在重新渲染后执行以下代码,它会立即重新渲染。此外,我的React应用程序也是如此: 当运行以及值与状态变量的内容不
问题内容: 什么是反射,为什么有用? 我对Java特别感兴趣,但是我认为原理在任何语言中都是相同的。 问题答案: 名称反射用于描述能够检查同一系统(或本身)中的其他代码的代码。 例如,假设您在Java中有一个未知类型的对象,并且想在该对象上调用“ doSomething”方法(如果存在)。除非对象符合已知的接口,否则Java的静态类型化系统并不是真正为支持该类型而设计的,但是使用反射,您的代码可以
问题内容: 什么是java反射,为什么有用? 问题答案: 名称反射用于描述能够检查同一系统(或本身)中其他代码的代码。 例如,假设你在Java中有一个未知类型的对象,并且你想在该对象上调用“ doSomething”方法(如果存在)。除非对象符合已知的接口,否则Java的静态类型化系统并不是真正为支持该类型而设计的,但是使用反射,你的代码可以查看该对象并确定其是否具有名为“ doSomething