useEffect和SocketIO无限渲染,为什么会发生?

时间:2019-04-30 10:04:22

标签: reactjs socket.io react-router-v4 react-hooks

我正在使用套接字中的useEffect Hook获取数据。每次获得响应时,都会重新渲染一个特定的组件,但是我不会将任何套接字数据传递给该组件。

代码:

  const App = () => {
  const isMounted = React.useRef(false);
  const [getSocketData, setSocketData] = useState([]);

  useEffect(() => {
    console.log('[App.js] Mounted!');
    isMounted.current = true;
    const socket = socketIOClient(process.env.REACT_APP_BOARD);
    socket.on('ServersInfo', (data) => {
      if (isMounted.current) {
        setSocketData([...data]);
      }
    });
    socket.on('connect_error', () => {
      if (isMounted.current) {
        setSocketData([]);
      }
      console.log('Connection error!');
    });
    return (() => {
      isMounted.current = false;
      socket.disconnect();
      console.log('[App.js] unmounted');
    });
  }, []);

  const routes = (
    <Switch>
      <Route path={['/', '/users/:id']} exact component={() => <MainPage axiosInstance={axiosInstance} />} />
      <Route path='/servers' render={(spProps) => <ServerPing {...spProps} />} />
      <Route render={(nfProps) => <NotFoundComponent {...nfProps} />} />
      {/* <Redirect to='/' /> */}
    </Switch>
  );
  return (
    <div className="App">
      <Layout>
        <Suspense fallback={<p>Loading...</p>}>
          {routes}
        </Suspense>
      </Layout>
    </div>
  );
};

export default App;

我的组件是什么样的: -App.js -布局(不重新呈现)(有3个子级)-MainPage(无限重新呈现),ServerPing(不重新呈现),NotFoundComponent(不重新呈现)

问题是:为什么MainPage组件无限渲染? 我的意思是,当套接字数据获取异常行为时,MainPage Component及其子级将再次卸载并安装。

MainPageComponent:

const MainPage = ({ axiosInstance, ...props }) => {

  const isMounted = React.useRef(false);
  const [loadingPage, setLoadingPage] = useState(true);
  const [usernames, setUsernames] = useState([]);
  const [currentDay] = useState(new Date().getDay());

  useEffect(() => {
    isMounted.current = true;
    console.log('[MainPage.js] Mounted!');
    getUsers();
    return () => {
      console.log('[MainPage.js] Unmounted!');
      isMounted.current = false;
    };
  }, []);

  const getUsers = async () => {
    try {
      const res = await axiosInstance.get('/users');
      const newData = await res.data;
      const newArray = [];
      newData.map(user => (
        newArray.push({id: user._id, flag: user.flag, text: user.name, value: user.name.toLowerCase()})
      ));
      if (isMounted.current) {
        setUsernames(newArray);
        setLoadingPage(false);
      }
    } catch {
      if (isMounted.current) {
        setLoadingPage(false);
      }
    }
  };

  return...

1 个答案:

答案 0 :(得分:1)

问题是您在component上使用render道具,而不是render the MainPage道具,如果有回调传递给组件道具

下面的代码应解决此问题

<Route 
    path={['/', '/users/:id']} 
    exact 
    render={(props) => <MainPage {...props} axiosInstance={axiosInstance} />} 
/>

react-router-dom文档

  

当您使用组件(而不是下面的渲染器或子代)时,   路由器使用React.createElement从   给定的组件。也就是说,如果您向   组件属性,您将在每个渲染中创建一个新组件。这个   导致现有组件的卸载和新组件的安装   安装而不只是更新现有组件。使用时   用于内联渲染的内联函数,请使用render或   children道具(如下)。