Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

580
Visualizações
yarn workspaces and lerna cause Invalid Hook call

I think this is a duplicate React problem

Current behavior : In the container project, it works fine when I route to sub-app/foo. But when I route to sub-app I get the following error :

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
 You might have mismatching versions of React and the renderer (such as React DOM)
 You might be breaking the Rules of Hooks
 You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

Notice: sub-app/foo will get a class component. sub-app will get a React hooks component

Expected behavior: The result I expect is that the subApp code will work fine in the container

The Project Structure:

/mono-repo
  packages
  - container
  - subApp
// /packages/container/src/App.js
import React from 'react'
import { BrowserRouter, Switch, Route, Link } from 'react-router-dom';
import About from './About';
import Header from './Header';
import Loadable from 'react-loadable'

const Logo = () => {
  return <div>LOGO</div>
}

const loadableComponent = (loader) => {
  return Loadable({
    loader: () =>
      loader().then(
        (res) => {
          return res
        },
        (e) => () => {
          console.log(e)
        }
      ),
    loading() {
      return (
        <div>loading</div>
      )
    }
  })
}

const loadSubApp = (subAppInfo) => {
  const { name, host } = subAppInfo
  return new Promise((resolve, reject)=> {
    fetch(`${host}/${name}/asset-manifest.json`)
      .then(res => res.json())
      .then(manifest => {
        const script = document.createElement('script');
        script.src = `${host}${manifest.files['main.js']}`;
        const timeout = setTimeout(()=>{
          console.error(`MicroApp ${name} timeout`);
          reject(new Error(`MicroApp ${name} timeout`));
        },20000)
        script.onload = () => {
          clearTimeout(timeout)
          const app = window[name]
          console.log({app, name})
          console.log(`MicroApp ${name} loaded success`);
          resolve(app)
        }
        script.onerror = (e) => {
          clearTimeout(timeout);
          console.error(`MicroApp ${name} loaded error`, e);
          reject(e)
        }
        document.body.appendChild(script);
      })
  })
}

const subLoader = (name) => async () => {
  const App = await loadSubApp({ name: 'subApp', host: process.env.REACT_APP_SUBAPP_HOST })
  console.log({App, window})
  return App[name]
}



const App = () => {
  return (
    <BrowserRouter>
      <React.Fragment>
        <Logo />
        <ul>
          <li>
          <Link to="/">Home</Link>
          </li>
          <li>
          <Link to="/header">header</Link>
          </li>
          <li>
          <Link to="/sub-app">subApp</Link>
          </li>
          <li>
          <Link to="/sub-app/foo">subApp foo</Link>
          </li>
          
        </ul>
        <Switch>
          <Route exact path="/" component={About} />
          <Route exact path="/header" render={() => <Header /> }/>
          <Route exact path="/sub-app/foo" render={()=> {
            const RenderSubApp = loadableComponent(subLoader('Foo'))
            return <RenderSubApp />
          }}/>
          <Route exact path="/sub-app" render={()=> {
            const RenderSubApp = loadableComponent(subLoader('Count'))
            return <RenderSubApp />
          }}/>
        </Switch>
      </React.Fragment>
    </BrowserRouter>
  )
}

// /packages/subApp/config-overrides.js
const {
  override,
  // addWebpackAlias
} = require("customize-cra");
// const path = require("path");

const dropConsole = () => {
  return (config) => {

    if (config.optimization.minimizer) {
      config.optimization.minimizer.forEach((minimizer) => {
        if (minimizer.constructor.name === "TerserPlugin") {
          minimizer.options.terserOptions.compress.drop_console = true;
        }
      });
    }
    return config;
  };
};

const optBuild= () => config => {
  config.optimization.runtimeChunk = false;
  config.optimization.splitChunks = {
    cacheGroups: {
      default: false,
    },
  }; 
  return config
}

const disableSourceMap = () => (config) => {
  if (process.env.NODE_ENV === "production") {
    config.devtool = false;
  }
  return config;
};

const customizeCraOverride = override(
  disableSourceMap(),
  dropConsole(),
  optBuild(),
  // addWebpackAlias({
  //   'react': path.resolve(__dirname, '../container/node_modules/react'),
  //   'react-dom': path.resolve(__dirname, '../container/node_modules/react-dom')
  // })
);

const webpack = (config, env) => {
  const webpackConfig = customizeCraOverride(config, env);

  return {
    ...webpackConfig,
    output: {
      ...webpackConfig.output,
      library: "subApp",
      libraryTarget: 'window',
    },
    // externals: {
    //   'react': 'react',
    //   'react-dom': 'react-dom'
    // },
  };
};

module.exports = {
  webpack,
};

The project link bug-demo

those solution doesn't work for me

  • https://reactjs.org/warnings/invalid-hook-call-warning.html
  • https://github.com/facebook/react/issues/13991
  • https://github.com/facebook/react/issues/15315
  • Solve having more than one copy of React in the same app
  • Yarn Workspaces and Invalid Hook call
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

I am not sure if this completely solves your problem but the error goes away and the routes work correctly. Nothing loads, I am pretty sure that I don't have the correct environment variables. But, basically you just had some faulty router code in your /packages/container/src/App.js file. I cloned the repository and this is what I changed it to:

    <Switch>
      <Route exact path="/" component={About} />
      <Route exact path="/header" render={() => <Header /> }/>
      <Route exact path="/sub-app" render={()=> {
        const RenderSubApp = loadableComponent(subLoader('Count'))
        return <RenderSubApp />
      }}>
        <Route exact path="/foo" render={()=> {
          const RenderSubApp = loadableComponent(subLoader('Foo'))
          return <RenderSubApp />
        }}/>
      </Route>
    </Switch>

Notice how the /foo route becomes a child of the /sub-app route. Although the error is gone React still shows a warning message: Warning: You should not use <Route render> and <Route children> in the same route; <Route render> will be ignored. I am not exactly sure how lerna works, but there might be some workaround for this.

Check out this section of the react-router docs.

over 4 years ago · Santiago Trujillo Relatório

0

Finally solved this problem.

// /packages/subApp/config-overrides.js

 ...

const webpack = (config, env) => {
  const webpackConfig = customizeCraOverride(config, env);

  return {
    ...webpackConfig,
    output: {
      ...webpackConfig.output,
      library: "subApp",
      libraryTarget: 'window',
    },
    externals: {
       'react': 'React',
       'react-dom': 'ReactDOM'
    },
  };
};
module.exports = {
  webpack
};

// packages/container/src/index.js

...

export {
  React,
  ReactDOM
}
// packages/container/config-overrides.js

  ...

const webpack = (config, env) => {
  const webpackConfig = customizeCraOverride(config, env);
  return {
    ...webpackConfig,
    output: {
      ...webpackConfig.output,
      libraryTarget: 'umd',
    },
  }
};
module.exports = {
  webpack
};
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda