Just adding useState hook statement causing component to rerender - reactjs

I have created a basic create-react-app and added the below statement
const [stateA, setStateA] = useState(false);
and I have put a console.log inside my component.
The complete component code is
import React, { useState } from 'react';
import logo from './logo.svg';
import './App.css';
const App = () => {
const [stateA, setStateA] = useState(false);
console.log("rendered");
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
It is showing "rendered" twice. Can any one tell why this is happening ?

If you notice index.js (as create-react-app now uses React.StrictMode by default ) file you may have a wrapper called React.StrictMode which is responsible for this extra re-render. The wrapper will invoke render, constructor and other lifecycle methods to detect side effects. So this is expected.
You can read more here: https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects
Hope this helps!

Related

Is it possible to pass different props from two different files in React?

Suppose I am calling a Component from the index.js and the same component is called off from a different file with a completely different set of props inside a return value. The below images are the two files and the component itself. The Modal component has a dependency on the Home component's toggle state. It will only render when the toggle is true, which is controlled by the button in Home Component. Keep in mind I'm rendering the Modal component in App.js and in Home.js
**This is a small demo of a more realistic situation.
After running this application Modal component is not rendering at all.
So the question is why is this happening internally and how to resolve this situation?
import React, {useState} from 'react'
import logo from './logo.svg';
import './App.css';
import Home from './components/Home';
import Modal from './components/Modal';
function App() {
const [logoR, setLogoR] = useState(logo);
const [currDate, setCurrDate] = useState(new Date());
console.log(currDate);
return (
<div className="App">
<header className="App-header">
<img src={logoR} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
<Home/>
<Modal logoR={logoR} currDate={currDate} />
</header>
</div>
);
}
export default App;
Github repo - React-props
In your handleClick() your return the Modal but nothing is being done with that. It's not being inserted into the DOM anywhere.
Something like this might get you closer.
import React, {usestate} trom 'react' 7.2K (gzipped: 3K)
import Modal from './Modal';
const Home = () => {
const [toggle, set Toggle] = usestate(false);
console.log(toggle);
const handleclick () => {
setToggle(!toggle);
}
return (
<div>
<button
className="App-button"
onclick={handleclick)>
whats up!
</button>
<Modal toggle={toggle} />
</div>
}
export default Home
I would suggest checking out react portals if you have a modal that you will want to trigger from various parts of the app. They have a good example of how to use this with a modal.
https://reactjs.org/docs/portals.html

React error with code splitting (Argument type function() is not assignable to parameter type)

I am trying to split my code using React.Lazy() with Route-based code splitting (https://reactjs.org/docs/code-splitting.html)
For example that's the component (Reports.jsx)
import React from 'react';
const Reports = () => {
return <div>Reports</div>;
};
export default Reports;
And I have in my route.js:
const LazyReports = React.lazy(() => import ('../../containers/team/reports/Reports'));
and I'm getting this error, and the bundle is not loaded.
Argument type function(): Promise<{readonly default?: function()}> is not assignable to parameter type () => Promise<{default: ComponentType}>   Type Promise<{readonly default?: function()}> is not assignable to type Promise<{default: ComponentType}>
I figured out it's not related to the routing, but I don't know why it doesn't recognize the component as "ComponentType"
I am not sure about the complete code but below code is working fine with lazy code syntax. I feel above seem ok to me. Hoping the container code is only have above component code.
One thing you can do , delete the build folder and build again with yarn build/npm build.
Below is simple code without any router /redux.
import React from 'react';
import logo from './logo.svg';
import './App.css';
const LazyReports = React.lazy(() => import ('./Reports'))
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<LazyReports/>
</div>
);
}
export default App;

Can't find module TS2307 in React

import React from "react";
import logo from "./logo.svg";
import text from "./compiler/test/index.txt";
import "./App.css";
const App: React.FC = () => {
// const compiler = new Compiler("../test/index.jack");
// compiler.save();
console.log("text: ", text);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
};
export default App;
I'm using react-app-rewired to override webpack configuration, without ejecting.
This component reads a .txt file and logs its content, but there is an error, Cannot find module './compiler/test/index.txt'. TS2307 in the third line of import.
As my comment seemed to resolve the issue, here as an official answer:
You probably just need to declare the type .txt somewhere in your typescript definitions. For create-react-app, this would be in react-app-env.d.ts. E.g.:
declare module '*.txt' {
const content: string;
export default content;
}

Jest snapshot testing not generating appropriate snapshot and passing

I'm new at jest testing. Now I'm trying to test my react components using snapshot testing. I've encountered such problem: jest only updates snapshot for AppComponent, but does not for another component, also it passes all both snapshot tests. What's wrong?
Have tried passing names to snapshot toMatchSnapshot(), have tried to change type of TestComponent from function to class extending Component, have tried deleting old snapshots and testing again, all in wain. Also, tried to render TestComponent in AppComponent below AppComponent default html and it caused updating AppComponent snapshot only.
AppComponent
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { TestComponent } from './TestComponent';
export function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
Learn React
</a>
</header>
</div>
);
}
export default App;
AppComponent test
import React from 'react';
import ReactDOM from 'react-dom';
import { App, reverseOfReverse, addTwoIntegers } from './App';
import renderer from 'react-test-renderer';
describe('snapshot tests', () => {
test('matches the snapshot', () => {
const tree = renderer.create(<App />).toJSON();
expect(tree).toMatchSnapshot('AppComponentSnapshot');
});
});
AppComponent snapshot
// Jest Snapshot v1
exports[`snapshot tests matches the snapshot: AppComponentSnapshot 1`] = `
<div
className="App"
>
<header
className="App-header"
>
<img
alt="logo"
className="App-logo"
src="logo.svg"
/>
<p>
Edit
<code>
src/App.js
</code>
and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
rel="noopener noreferrer"
target="_blank"
>
Learn React
</a>
</header>
</div>
`;
TestComponent
import logo from './logo.svg';
import React, { Component } from 'react';
export class TestComponent extends Component {
render() {
return (
<div className="TestComponent">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
Learn React
</a>
</header>
<div>lola</div>
<div>amanda</div>
</div>
);
}
}
export default TestComponent;
TestComponent test
import React from 'react';
import renderer from 'react-test-renderer';
import { TestComponent } from './TestComponent';
describe('snapshot for second component', () => {
test('matches second snapshot', () => {
const tree = renderer.create(<TestComponent />).toJSON;
expect(tree).toMatchSnapshot('TestComponentSnapshot');
});
});
TestComponent snapshot
// Jest Snapshot v1
exports[`snapshot for second component matches second snapshot: TestComponentSnapshot 1`] = `[Function]`;
I expected that snapshot test would also fill TestComponent snapshot with appropriate snapshot, or the test would fail, but neither happened.
I just faced this problem too. Spent an hour to realize that toJSON is missing a pair of parentheses. It's supposed to be a function call toJSON() instead of just toJSON. How silly

React - difference between function and component

I'm just starting to learn React, and I noticed that the App.js component which is initially created differs from the one in the tutorials (which are pretty recent).
The one generated looks like this:
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
The one in the tutorials looks similar, but looks something like this:
import React from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
)
}
export default App;
Have there been any recent changes to the default App.js?
Yes, this is a quite recent change. It was merged in March 2019.
https://github.com/facebook/create-react-app/pull/6451
In practice there's no difference between the two version of App.js, since the class only implements the render method. Using a class component here is perfectly fine, and there's no plans to get remove class components from react.js.
You will have to ask the create-react-app team why they changed it. They presumably want to use function components wherever possible. With the introduction of hooks in react 16.8, almost everything that used to require class components can now be done using function components.
One is called a functional component and does not have a this.state you can refer to, but rather the UI is controlled by this.props. The other is a full-blown component where you can have this.state. Also, functional components do not have render methods, they just return JSX.
Functional components are usually more performant and should be used when you don't need to use this.setState within a component.
If you wanted to toggle a button on and off within a functional component, you would NOT be able to it using its INTERNAL state - because it does not have one in the first place. You would have to refer to the PARENT component using this.props.isButtonClicked for example like this:
class ParentComponent extends Component {
constructor(props) {
super(props);
this.state = {
isButtonClicked: true,
}
}
render() {
return (
<FunctionalComponent isButtonClicked={this.state.isButtonClicked} />
)
}
}
// | here you can grab the variable
export const FunctionalComponent = ({ isButtonClicked }) => {
if (isButtonClicked) {
return (...clickedButton)
}
return (...unclickedButton)
}
As you can see here the state of the functional-component is defined by the PARENT. The parent's state decides whether it is clicked or not. This is the benefit of having a class-component.
On the other hand, you could make a button with its own internal state to decide if its clicked or no.
EDIT: So with React hooks you can now have state within functional components. My bad.

Resources