systemjs to load react function component use hooks run error。 - reactjs

I use webpack to bundle a react function component use useState and set output.libraryTarget: system。
import React, { useState } from "react";
const Foo = () => {
const [str] = useState("workd");
return <div>hello, {str}</div>;
};
export default [Foo];
In other react project I use systemjs to load the above component lik blow
<script type="systemjs-importmap">
{
"imports": {
"baseC": "http://localhost:8000/static/js/bundle.js"
}
}
</script>
<script src="https://cdn.jsdelivr.net/npm/systemjs/dist/system.js"></script>
<script>
System.import("baseC");
</script>
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
window.System.import("baseC").then((res) => {
const Components = res.default[0];
console.log("Components", Components);
ReactDOM.render(
<React.StrictMode>
<Components />
</React.StrictMode>,
document.getElementById("root")
);
});
then I get the error
react.development.js:1476 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
and the whole demo in https://github.com/ytudt/react-systemjs
what should I do to solve this problem? thanks.

Related

React. why can't I insert a component from a third party library?

I have the latest version react react#17.0.1 and use the react-player library, import the player, insert it into the layout and get errors:
------- 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
------- VM30105 react-dom.development.js:20085 The above error occurred in the component: at Provider
(webpack-internal:///./node_modules/react-redux/es/components/Provider.js:14:20)
Consider adding an error boundary to your tree to customize error
handling behavior.
------- Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your
application. To fix, cancel all subscriptions and asynchronous tasks
in a useEffect cleanup function.
As soon as I remove the Provider store = {store} /Provider wrapper everything works fine, which may be the problem, also when I try to add functional components I created, the same error occurs.
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { rootReducer } from "../redux/rootReducer.js";
import ReactPlayer from 'react-player'
import { compose, createStore } from "redux";
import { Provider } from "react-redux";
const store = createStore(
rootReducer,
compose(
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
const app = (
<Provider store={store}>
<App />
</Provider>
);
function App() {
return (
<div>
<ReactPlayer url='https://www.youtube.com/watch?v=ysz5S6PUM-U' />
</div>
);
}
export default App;
if (document.getElementById("app")) {
ReactDOM.render(app, document.getElementById("app"));
}

Unit testing Chakra UI with Jest

Currently I am trying to unit test my application that is built with Create-React-App with typescript, and it is styled with chakraui. Chakrui includes a component ThemeProvider that must wrap the entire application as such.
This is my index.tsx file
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { ThemeProvider, CSSReset } from "#chakra-ui/core/dist";
import { theme } from "#chakra-ui/core/dist";
ReactDOM.render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<CSSReset />
<App />
</ThemeProvider>
</React.StrictMode>,
document.getElementById("root")
For every unit test that I write, I am having to wrap the component with ThemeProvider for the test to pass:
import React from "react";
import { render } from "#testing-library/react";
import { ThemeProvider } from "#chakra-ui/core/dist";
import App from "./App";
describe("<App />", () => {
test("smoke test", () => {
render(
<ThemeProvider>
<App />
</ThemeProvider>
);
});
});
But this is very verbose, and must be done for every test that I write. Is there a way to do this just once in each .test.tsx file?
You could create your own theme wrapper function
import React from "react";
import { ThemeProvider } from "#chakra-ui/core/dist";
export const ThemeWrapper = ({ children }) => (
<ThemeProvider>{children}</ThemeProvider>
);
And then specify the wrapper in the test
import React from "react";
import { render } from "#testing-library/react";
import { ThemeWrapper } from "../testUtils";
import App from "./App";
describe("<App />", () => {
test("smoke test", () => {
render(<App />, { wrapper: ThemeWrapper });
});
});
This marginally reduces the code for testing. You may be able to also go the route of creating a custom render function (following the steps for redux).
It could look something like
import React from "react";
import { render } from "#testing-library/react";
import { ThemeProvider } from "#chakra-ui/core/dist";
export const renderWithTheme = ui => {
const Wrapper = ({ children }) => (
<ThemeProvider>{children}</ThemeProvider>
);
return render(ui, { wrapper: Wrapper });
};
Basically the same as the wrapper above, but more integrated into a test render function. You can adjust the function signature a bit as well if you need to pass in a theme object, or other render options, this is just a simple example.
Now the test looks like
import React from "react";
import { renderWithTheme } from "../testUtils";
import App from "./App";
describe("<App />", () => {
test("smoke test", () => {
renderWithTheme(<App />);
});
It might be the case that Jest might be mocking your imports from #chakra-ui/core/dist (depending on your jest configuration) which might be resulting your imported chakra-ui components to be undefined.
Importing the Theme Provider and wrapping it everytime with your renders might be one way to do it. The problem might arise when you have multiple components in your index.tsx. So, you might not want to import each and every component.
In that case, you will want to import the actual components from #chakra-ui/core.
The best way (according to me) to do so in Jest is:
jest.mock("#chakra-ui/core", () => {
const ui = jest.requireActual("#chakra-ui/core");
return {
...ui,
customKey: 'customValue',
};
})
This way you can even add custom function and key-values to the imported module.

React - TypeError: Cannot read property 'lazy' of undefined

I followed this guide to enable TypeScript for an existing React App. When the app is started the following error appears: TypeError: Cannot read property 'lazy' of undefined
React version is 16.8.0 (react, react-dom, #types/react, react-test-renderer).
index.js (due to stackoverflow restrictions on size of code vs text not all imports are shown)
import React, { Suspense } from 'react';
const AsyncApp = React.lazy(() => import('App'));
/** wrap App component in a fallback component for lazy loading */
const App = (
<div>
<Suspense
fallback={<LoadingScreen />}
>
<AsyncApp loggedIn />
</Suspense>
</div>
);
async function renderApp() {
if (document.title !== CONFIG.appName) {
document.title = CONFIG.appName;
}
ReactDOM.render(App, document.getElementById('root'));
}
/** init app */
renderApp();
You have to import React.
import React from "react";
Cannot read property 'lazy' of undefined
This means that React is undefined. Your file needs to import react. Add the following to the top of your index.js:
import React from 'react';
If you have the import already then make sure your tsconfig.json has "esModuleInterop" : true.

useState() Breaks Gatsbyjs/React

I have imported useStats into my index page but when I use it it breaks gatsby/react and I get this error:
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 fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
I tried to trouble shoot using this from the site:
// Add this in node_modules/react-dom/index.js
window.React1 = require('react');
// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);
But I got back true.
Here is my code:
import React, { useState } from "react";
import { Link } from "gatsby";
// components
import Layout from "../components/Layout/Layout";
import SEO from "../components/seo";
import IndexComponent from "../components/IndexComponent/IndexComponent";
const IndexPage = () => {
const [sku] = useState();
return (
<Layout>
<SEO title="Home" />
<IndexComponent />
</Layout>
);
};
export default IndexPage;
1.) you need [sku, setSku] = useState().
2.) Where are you rendering IndexPage? Are you doing IndexPage() instead of <IndexPage />?
I think It is a terminal Issue with windows.
Seams to work fine with bash.

Can we integrate react component into Aurelia project?

I have created one react component and build it using webpack and deployed on server. I want to integrate this component into Aurelia Project.
I tried using below npm module:
https://www.npmjs.com/package/aurelia-react-loader
In above module mentioned, component name need pass into html file. like in example my-react-component.js is passing into html file.
But my React Component is loading into root in html tag using below code:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render((
<App/>
), document.getElementById('root'));
and after running webpack module, it is creating one JavaScript file that is called index_bundle.js file. Here imported App module is main js component. It is rendering into index.html on root element via ReactDOM.
So I am not sure, How I am going to integrate React component link or url into Aurelia application?
Please let me know if you have any doubts in question. I can do explain in detail.
Thanks in advance.
Harish
Yeah, it's really easy to integrate a react component in to an Aurelia app. Check out my project where I do just that here: https://github.com/ashleygrant/aurelia-loves-react
I'm not even using the loader plugin you mentioned.
Here's how to wrap a third-party react component in an Aurelia custom element:
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDatePicker from 'react-datepicker';
import { noView, bindable, inject } from 'aurelia-framework';
#noView(['react-datepicker/react-datepicker.css'])
#inject(Element)
export class DatePicker {
#bindable selectedDate;
#bindable onChange;
constructor(element) {
this.element = element;
}
selectedDateChanged() {
this.render();
}
render() {
ReactDOM.render(
<ReactDatePicker
selected={this.selectedDate}
onChange={date => this.onChange({ date: date })}
/>,
this.element
);
}
// How to use native DOM events to pass the changed date
/*render() {
ReactDOM.render(
<ReactDatePicker
selected={this.selectedDate}
onChange={date => {
let event = new CustomEvent('change', { 'detail': date });
// Dispatch the event.
this.element.dispatchEvent(event);
}
}
/>,
this.element
);
}*/
}
And here's how to do it while using a custom react component that is part of the Aurelia project:
import React from 'react';
import ReactDOM from 'react-dom';
import { noView, bindable, inject } from 'aurelia-framework';
import FormattedDate from '../react-components/formatted-date';
#noView()
#inject(Element)
export class ReactDate {
#bindable date;
#bindable format = 'dddd, MMMM D, YYYY';
constructor(element) {
this.element = element;
}
dateChanged() {
this.render();
}
formatChanged() {
this.render();
}
render() {
ReactDOM.render(
<FormattedDate
date={this.date}
format={this.format}
/>,
this.element
);
}
}
As you can see, it's pretty simple. I like doing it by hand rather than using the loader as I can set up databinding for each property so it works in a more "Aurelia-ey" way.

Resources