React路由器组件呈现非常错误的状态

时间:2020-10-30 15:59:16

标签: reactjs react-router-v4

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。如果您在return null内将if (s === 'aa')注释掉,它将按预期呈现bb

黑客正在发生什么?

1 个答案:

答案 0 :(得分:1)

如果您使用一些日志(下面的代码),它将很清楚。查看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 ),因此输出“正在运行的侦听器1”从组件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);