【问题标题】:useEffect and SocketIO Infinite Rerendering, why is it happening?useEffect 和 SocketIO Infinite Rerendering,为什么会这样?
【发布时间】:2019-04-30 10:04:21
【问题描述】:

我正在使用来自套接字的 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;

我的组件是什么样子的: - 应用程序.js - 布局(不重新渲染)(有 3 个子级) - MainPage(无限重新渲染)、ServerPing(不重新渲染)、NotFoundComponent(不重新渲染)

问题是:为什么 MainPage 组件会无限重新渲染? 我的意思是 MainPage 组件及其子组件在获取套接字数据时卸载并再次安装,这是一种奇怪的行为。

主页面组件:

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...

【问题讨论】:

  • 你有 MainPage 的代码 sn-p 吗? axiosInstance 定义在哪里?
  • @Kunukn 上传了 sn-p。但我猜 axiosInstance 很好

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


【解决方案1】:

问题是您使用component prop 而不是render prop 到render the MainPage,如果组件prop 有回调,它将在任何重新渲染App 组件时重新安装组件。

下面的代码应该可以解决问题

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

根据 react-router-dom 文档

当你使用组件(而不是渲染或子,下面) 路由器使用React.createElement 从 给定的组件。这意味着如果您向 组件道具,您将在每次渲染时创建一个新组件。这 导致现有组件卸载和新组件 安装而不是仅仅更新现有组件。使用时 用于内联渲染的内联函数,使用 renderchildren 道具(下)。

【讨论】:

    猜你喜欢
    • 2018-10-15
    • 2011-06-03
    • 2018-06-08
    • 2014-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多