React 路由器组件呈现一个非常错误的状态
React router component render a very wrong state
import React, { useEffect, useState } from 'react'
import { Route } from 'react-router-dom'
import { BrowserRouter as Router } from 'react-router-dom'
export default function Test() {
const s = useS()
if (s === 'aa') {
return null
}
return (
<Router>
<Route component={MyCpt}></Route>
</Router>
)
}
function MyCpt() {
const s = useS()
return <h1>{s}</h1>
}
function useS() {
const [state, setState] = useState('aa')
useEffect(() => {
subscribe(setState)
}, [])
return state
}
const listeners = []
function subscribe(cb) {
listeners.push(cb)
}
setTimeout(() => {
listeners.forEach((cb) => {
cb('bb')
})
}, 2000)
这是完全可运行的代码,简单而连线。如您所见,MyCpt
将从 useS
呈现的状态最终将变为 bb
(2 秒后)。但是,无论您等待多长时间,它都会呈现 aa
。如果您在 if (s === 'aa')
中注释掉 return null
,它将按预期呈现 bb
发生了什么黑客攻击?
如果你使用一些日志(下面的代码),它会很清楚。看看 console.log
:
1. Test aa
2. Subscribed
3. Running listeners 1
4. Test bb
5. MyCpt aa
6. Subscribed
步骤 1-2) 首先记录“Test aa”,订阅发生在钩子内,但由于返回 null,组件退出。
步骤 3-4) 之后,注册的侦听器(注意到目前为止只有一个侦听器已注册,请参阅计数 1)是 运行,因此输出“运行 listeners 1”,然后从组件 Test
.
再次打印“Test bb”
步骤 5-6) 现在,MyCpt
正在 运行,并且发生订阅,但不会再次调用侦听器。
这是带有日志的代码:
import React, { useEffect, useState } from "react";
import { Route } from "react-router-dom";
import { BrowserRouter as Router } from "react-router-dom";
export default function Test() {
const s = useS();
console.log("Test", s);
if (s === "aa") {
return null;
}
return (
<Router>
<Route component={MyCpt}></Route>
</Router>
);
}
function MyCpt() {
const s = useS();
console.log("MyCpt", s);
return <h1>{s}</h1>;
}
function useS() {
const [state, setState] = useState("aa");
useEffect(() => {
subscribe(setState);
}, []);
return state;
}
const listeners = [];
function subscribe(cb) {
console.log("Subscribed");
listeners.push(cb);
}
setTimeout(() => {
console.log("Running listeners", JSON.stringify(listeners.length));
listeners.forEach((cb) => {
cb("bb");
});
}, 2000);
import React, { useEffect, useState } from 'react'
import { Route } from 'react-router-dom'
import { BrowserRouter as Router } from 'react-router-dom'
export default function Test() {
const s = useS()
if (s === 'aa') {
return null
}
return (
<Router>
<Route component={MyCpt}></Route>
</Router>
)
}
function MyCpt() {
const s = useS()
return <h1>{s}</h1>
}
function useS() {
const [state, setState] = useState('aa')
useEffect(() => {
subscribe(setState)
}, [])
return state
}
const listeners = []
function subscribe(cb) {
listeners.push(cb)
}
setTimeout(() => {
listeners.forEach((cb) => {
cb('bb')
})
}, 2000)
这是完全可运行的代码,简单而连线。如您所见,MyCpt
将从 useS
呈现的状态最终将变为 bb
(2 秒后)。但是,无论您等待多长时间,它都会呈现 aa
。如果您在 if (s === 'aa')
中注释掉 return null
,它将按预期呈现 bb
发生了什么黑客攻击?
如果你使用一些日志(下面的代码),它会很清楚。看看 console.log
:
1. Test aa
2. Subscribed
3. Running listeners 1
4. Test bb
5. MyCpt aa
6. Subscribed
步骤 1-2) 首先记录“Test aa”,订阅发生在钩子内,但由于返回 null,组件退出。
步骤 3-4) 之后,注册的侦听器(注意到目前为止只有一个侦听器已注册,请参阅计数 1)是 运行,因此输出“运行 listeners 1”,然后从组件 Test
.
步骤 5-6) 现在,MyCpt
正在 运行,并且发生订阅,但不会再次调用侦听器。
这是带有日志的代码:
import React, { useEffect, useState } from "react";
import { Route } from "react-router-dom";
import { BrowserRouter as Router } from "react-router-dom";
export default function Test() {
const s = useS();
console.log("Test", s);
if (s === "aa") {
return null;
}
return (
<Router>
<Route component={MyCpt}></Route>
</Router>
);
}
function MyCpt() {
const s = useS();
console.log("MyCpt", s);
return <h1>{s}</h1>;
}
function useS() {
const [state, setState] = useState("aa");
useEffect(() => {
subscribe(setState);
}, []);
return state;
}
const listeners = [];
function subscribe(cb) {
console.log("Subscribed");
listeners.push(cb);
}
setTimeout(() => {
console.log("Running listeners", JSON.stringify(listeners.length));
listeners.forEach((cb) => {
cb("bb");
});
}, 2000);