ComponentDidMount called twice - reactjs

ComponentDidMount in my overarching App component is being called twice, and I can't figure out why. So far google suggests this is usually due to a lack of keys that means the app has to assume things have changed and delete everything instead of just the relevant portion of the DOM, but I stripped my app as bare as I can get reasonably get it and it's still happening.
index.tsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App global={{baseUrl: "http://localhost", port: 54887}} />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
reportWebVitals();
App.tsx:
import React from 'react'
import CurrentItems, { CurrentItemsProps } from './CurrentItems';
import Navigation, { NavigationProps } from './Navigation';
import { CombinedNavigationProps } from './Navigation';
import './App.css';
import { GlobalProps } from './GlobalProps';
interface AppProps extends GlobalProps {}
interface AppState {
navigation: NavigationProps;
}
class App extends React.Component<AppProps, AppState> {
constructor(props: AppProps){
super(props);
//this.onSelectedViewChange = this.onSelectedViewChange.bind(this);
}
componentDidMount(){
console.log("app did mount");
}
onSelectedViewChange(view: string) {
}
render(){
if(this.state === undefined || this.state === null){
return (<div>Loading...</div>);
} else {
return (
<div>
Loaded.
</div>
);
}
}
}
export default App;
Link to github for full code
Screenshot of console output:

Per #NicholasTower's comment, it's because I'm using strict mode. Seems like it's time to learn about Hooks! Guess I didn't go far enough in the ReactJS introduction documentation.

Related

How to stop invisible console log in next js?

I'm using react-redux in my next js application. I'm calling the request to create a store when there is a request in my _app.js but there is some message logged in my console every time I route to a page.
This is its screenshot
I feel this is a bit annoying, I've search all over my code but I can't find what is logging here. Here is my _app.js for reference.
import Layout from '../components/Layout/Layout';
import '../styles/globals.css';
import { initializeParse } from '#parse/react-ssr';
import { Provider } from 'react-redux';
import withRedux from 'next-redux-wrapper';
import React from 'react';
import store from '../redux/store';
import App from 'next/app'
import TimeAgo from 'javascript-time-ago'
import en from 'javascript-time-ago/locale/en'
import ru from 'javascript-time-ago/locale/ru'
TimeAgo.addLocale(en)
class MyApp extends App{
static async getInitialProps({Component,ctx}){
const appProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {} ;
return {appProps: appProps};
}
render() {
const {Component,appProps} = this.props;
return(
<Provider store={store}>
<Layout>
<Component {...appProps} />
</Layout>
</Provider>
);
}
}
const makeStore = () => store;
export default withRedux(makeStore)(MyApp);
I would like find out what's going on
This was an issue with next-redux-wrapper.
Ref.:
https://github.com/kirill-konshin/next-redux-wrapper/issues/385
https://github.com/kirill-konshin/next-redux-wrapper/pull/384
It is fixed in this commit, release.
Please upgrade to v7.0.2 to resolve this problem.

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 Redux - Unable to resolve "./components/Provider" from "node_modules\react-redux\lib\index.js"

The development server returned response error code: 500 \n\n
Unable to resolve "./components/Provider" from "node_modules\react-redux\lib\index.js"
BodyX:
{"originModulePath":"C:\\Users\\MY PC\\Documents\\Projects\\snapfood-customer\\node_modules\\react-redux\\lib\\index.js","targetModuleName":"./components/Provider","message":"Unable to resolve module `./components/Provider` from `C:\\Users\\MY PC\\Documents\\Projects\\snapfood-customer\\node_modules\\react-redux\\lib\\index.js`: The module `./components/Provider` could not be found from `C:\\Users\\MY PC\\Documents\\Projects\\snapfood-customer\\node_modules\\react-redux\\lib\\index.js`. Indeed, none of these files exist:\n\n
my code is as below:
import React from 'react';
import store from './app/index';
import WelcomeScreen from './app/WelcomeScreen';
import { Provider } from 'react-redux';
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<WelcomeScreen/>
</Provider>
);
}
}

#withRouter Unexpected Token Error

Seems every time I have to setup React Router in a new project I run into something new possibly by version changes.
I am using reactjs and mobx state tree(though at this point have not used anything of it).
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import HomeComponent from './HomeComponent.js';
import {withRouter, Route} from 'react-router'
#withRouter
export default class App extends Component {
render() {
return (
<Route exact path='/' component={HomeComponent}/>
);
}
}
export default App;
When I run it I get
ERROR in ./src/components/App.js
Module build failed: SyntaxError /components/App.js: Unexpected token (6:0)
I also get some warning as well
Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
Edit
Per the comment from "Artem Mirchenko"
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'mobx-react';
import { useStrict } from 'mobx';
import createBrowserHistory from 'history/createBrowserHistory';
import {syncHistoryWithStore } from 'mobx-react-router';
import { Router } from 'react-router'
import AppContainer from './components/App';
const browserHistory = createBrowserHistory();
import stores from '../src/stores/Stores';
const history = syncHistoryWithStore(browserHistory, stores.routingStore);
ReactDOM.render(
<Provider {... stores}>
<Router history={history}>
<AppContainer />
</Router>
</Provider>,
document.getElementById('app')
);
import {RouterStore} from 'mobx-react-router';
const routingStore = new RouterStore();
const stores = {
routingStore
}
export default stores;
You need to install babel plugin transform-decorators-legacy.
Via yarn:
yard add --dev transform-decorators-legacy
Vie npm:
npm install --save-dev transform-decorators-legacy
And add in to plugins ket in you babel options:
{
// pressets ....
"plugins": ["transform-decorators-legacy"]
}

How to organize state with redux and react-router?

Redux advocates the use of a single store with a single state. However, with react-router you get multiple pages each having their own top-level root component.
How should one go about wiring up redux with a react-router app that has multiple pages? React-router 1.0 no longer lets you pass props to the routes so making the router the top level component that contains the state for all the pages is no longer possible nor is it feasible.
If you are using redux + react-router I would highly recommend using redux-router as well - this will allow you to keep route information in your store - I usually have the following setup.
redux-router: ^1.0.0-beta3 /
react-router": ^1.0.0-rc1 /
redux: "^3.0.2 /
react: "^0.14.0
//index.js [entry point]
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route } from 'react-router';
import { Provider } from 'react-redux';
import createStore from './utils/create-store';
import routes from './bootstrap/routes';
import { ReduxRouter } from 'redux-router';
const store = createStore(routes);
ReactDOM.render(
<Provider store={store}>
<ReduxRouter>
{routes}
</ReduxRouter>
</Provider>,
document.getElementById('root')
);
// create-store.js
import { applyMiddleware, createStore, combineReducers, compose } from 'redux';
import * as reducers from '../reducers/index';
import promiseMiddleware from './promise-middleware';
import { routerStateReducer, reduxReactRouter } from 'redux-router';
import history from './history'
/**
* Sets up the redux store. Responsible for loading up the reducers and middleware.
*
* #param routes
*/
export default function create(routes) {
const composedReducers = combineReducers({
router: routerStateReducer,
...reducers
});
const finalCreateStore = compose(applyMiddleware(promiseMiddleware),
reduxReactRouter({
routes,
history
}))(createStore);
let store = finalCreateStore(composedReducers);
return store;
}
// routes.js
import React from 'react';
import { Route } from 'react-router';
import App from './app';
module.exports = (
<Route component={App}>
...all your routes go here
</Route>
);
// app.js
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
export default class App extends React.Component {
render() {
const { props: { children } } = this;
return (
<div className="app-container">
{children}
</div>
);
}
}
So as you can see there is one higher order component that wraps the rest of your routes
Redux-router is no longer compatible with react-router v4, and the above solution will not work.
As such, I suggest utilzing redux-little-router. Unlike redux-router it is not dependent on react-router, but instead a replacement for it.
With it you can do things like:
Push to new routes from your async actions:
export function navigateAbout() {
return (dispatch) => {
dispatch(push('/about'))
}
}
See your router details (current path, querystring and params) inside redux-dev-tools, and access those details from you store like you would for any other prop:
function mapStateToProps(state) {
return {
string: state.router.query.string
}
}
PS. You can refer to or use this react boilerplate with redux-little-redux already implemented

Resources