useEffect和SocketIO Infinite Rerendering,为什么会发生?

问题描述 投票:1回答:1

我正在使用套接字中的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组件及其子组件再次卸载并重新装入。

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...
reactjs socket.io react-router-v4 react-hooks
1个回答
1
投票

问题是你使用component prop而不是render prop到render the MainPage,如果有一个组件道具的回调,它将重新安装App组件的任何重新渲染组件。

下面的代码应该解决问题

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

根据react-router-dom文档

当您使用组件(而不是渲染或子项,下面)时,路由器使用React.createElement从给定组件创建新的React元素。这意味着如果为组件prop提供内联函数,则每次渲染都会创建一个新组件。这导致现有组件卸载和新组件安装,而不是仅更新现有组件。使用内联函数进行内联渲染时,请使用renderchildren prop(下面)。

© www.soinside.com 2019 - 2024. All rights reserved.