react component render method being called twice for no reason - reactjs

import './App.css';
import SolarSystem from './components/solarSystem/solarSystem';
class App extends React.Component {
componentDidMount(){
console.log("mounting");
}
componentDidUpdate(){
console.log("updating");
}
//const [SSVisibility, setSSVisibility] = useState(true);
render(){
console.log("rendering app");
return (
<div className="App">ssssssssssssssssssssssssssssssss
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
export default App;
With this simple code, my render method is being called twice. And i cant understand why

It is because of strict mode, code below doesn't demonstrate it because SO will build it with production set true (I think).
class Strict extends React.Component {
componentDidMount() {
console.log('mounting strict');
}
componentDidUpdate() {
console.log('updating');
}
//const [SSVisibility, setSSVisibility] = useState(true);
render() {
console.log('rendering strict');
return (
<div className="App">
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
class NonStrict extends React.Component {
componentDidMount() {
console.log('mounting non strict');
}
componentDidUpdate() {
console.log('updating');
}
//const [SSVisibility, setSSVisibility] = useState(true);
render() {
console.log('rendering Non strict');
return (
<div className="App">
{/* <SolarSystem isShowing={"yolo"} toggle={"polo"}></SolarSystem> */}
</div>
);
}
}
const App = () => {
return (
<div>
<React.StrictMode>
<Strict />
</React.StrictMode>
<NonStrict />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related

this.props.xxxx is not a function

class UserForm extends React.Component {
constructor(props) {
super(props);
const { user } = props;
}
_cancelForm() {
this.props.onCancel();
}
render() {
return (
<button onClick={this._cancelForm.bind(this)}> Cancel </button>
);
}
}
class UserCreate extends React.Component {
_navigateToLogin() {
console.log("hi")
}
render() {
return (
<div>
<UserForm onCancel={this._navigateToLogin.bind(this)}/>
</div>
);
}
}
ReactDOM.render(
<UserCreate/>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
import React from 'react'
import { withRouter } from 'react-router-dom';
import UserForm from './UserForm'
import UsersService from '../services/UsersService'
class UserCreate extends React.Component{
_navigateToLogin() {
this.props.history.push('/homepage');
}
async _saveUser(user) {
await UsersService.createUser(user);
this._navigateToLogin();
}
render() {
return(
<div>
<UserForm
onCancel={this._navigateToLogin.bind(this)}
onSubmit={this._saveUser.bind(this)}
/>
</div>
);
}
}
export default withRouter(UserCreate)
import React from 'react'
import {
Button
} from '#material-ui/core'
export default class UserForm extends React.Component {
constructor(props) {
super(props);
const { user } = props;
this.state = {
...
}
_handleFormSubmit() {
const user = {
...
};
this.props.onSubmit(user);
}
_cancelForm() {
this.props.onCancel();
}
render () {
return (
<div style={{ width: '100%', height: 'auto', position: 'fixed', minWidth: '100%', minHeight: '100%', backgroundColor: '#50617C' }}>
<Button size="small" onClick={ this._cancelForm.bind(this) }>Back</Button>
<Button size="small" onClick={ this._handleFormSubmit.bind(this) }>Create</Button>
</div>
)
}
}
The error is present when I click the "Back" button on CreateAccountForm, it returns an error that says that the onCancel function is not a function. I'm sending it on the UserCreate by binding and I'm calling it on the function _cancelForm(). I was thinking that the error is that I'm missing something in the constructor according to some react documentation, I used before this method and it worked, right now I don't know what's happening.
The code you posted does not demonstrate the error, below is your code and it works just fine.
class UserForm extends React.Component {
constructor(props) {
super(props);
}
_cancelForm() {
this.props.onCancel();
}
render() {
return (
<button onClick={this._cancelForm.bind(this)}>
cancel
</button>
);
}
}
class UserCreate extends React.Component {
_navigateToLogin() {
console.log('in navigate login');
}
render() {
return (
<div>
<UserForm
onCancel={this._navigateToLogin.bind(this)}
/>
</div>
);
}
}
ReactDOM.render(
<UserCreate />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Can you provide a minimal snippet that reproduces the error you are getting?
You also don't need to bind the handler if you use arrow functions. For example:
_navigateToLogin = () => {//arrow function is automatically bound to this
console.log('in navigate login');
};
and
<UserForm onCancel={this._navigateToLogin} />

ReactJS Call Function of another Component react-router

I have implemented an app which uses react-router to handle the routes in my web-app. I want to trigger the function logintoggle which is on the Header.js component from a function from the Hompage.js component. The App.js has all the routes in one file.
Can anyone explain to me how this can be achieved with small code snippet?
App.js
render() {
const { location } = this.props;
return (
<IntlProvider
locale="a"
messages="s"
>
<Fragment>
<div>
<Headers />
<Switch>
<Route exact path="/women" component={HomePage} />
</Switch>
</div>
</Fragment>
</IntlProvider>
);
}
}
export default App;
Header
class Header extends React.Component {
constructor(props) {
super(props);
}
logintoggle(tab) {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
});
}
}
}
Homepage.js
class CheckOut extends Component {
constructor(props) {
super(props);
}
}
When you need to have a shared state among the components React.Context API is what you need. It allows you to create a separate context provider, which will provide the state and the methods to manipulate this state to all the components you need. In the example below I have a LoginContextProvider with activeTab state variable. I provide activeTab and setActiveTab to all the components inside LoginContextProvider's children. Header changes activeTab to 1, Homepage changes to 2 and LoginContextDebug represents the actual activeTab value.
const LoginContext = React.createContext(null);
const LoginContextProvider = ({ children }) => {
const [activeTab, setActiveTab] = React.useState(0);
return (
<LoginContext.Provider value={{ setActiveTab, activeTab }}>
{children}
</LoginContext.Provider>
);
};
const Header = () => {
// Use setActiveTab here
const { setActiveTab } = React.useContext(LoginContext);
return (
<div>
<h1>I am header</h1>
<button onClick={() => setActiveTab(1)}>Set activeTab to 1</button>
</div>
);
};
const Homepage = () => {
// Use setActiveTab here
const { setActiveTab } = React.useContext(LoginContext);
return (
<div>
<h1>I am homepage</h1>
<button onClick={() => setActiveTab(2)}>Set activeTab to 2</button>
</div>
);
};
const LoginContextDebug = () => {
const { activeTab } = React.useContext(LoginContext);
return (
<pre style={{ padding: 10, background: "lightgray" }}>
activeTab={activeTab}
</pre>
);
};
const App = () => (
<LoginContextProvider value={null}>
<Header />
<Homepage />
<LoginContextDebug />
</LoginContextProvider>
);
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Transferring from one component (page) to another component ( another page)

what I am trying to achieve here is being able to move to Page1 component from App component by clicking a button.
The result I am getting is
Page 1
Let's get started
Go!
The result I want to achieve is
Page 1
Please point out what I am doing wrong here. Thank you.
import React, { Component } from 'react';
import Page1 from './comps/Page1';
class App extends Component {
state = {
page:0
}
HandlePage = () => {
this.setState({
page:1
})
}
render() {
let comp = null;
if(this.state.page === 1){
comp = <Page1/>
}
return (
<div className="App">
{comp}
<h1>Let's get started!!</h1>
<div className="button">
<button
type="submit"
onClick={this.HandlePage}
>GO</button>
</div>
</div>
);
}
}
export default App;
//Page 1 Component
import React, { Component } from 'react';
class Page1 extends Component {
render() {
return (
<div className="App">
<h1>Page 1</h1>
</div>
);
}
}
export default Page1;
Here is a snippet of how you can achieve it by conditional rendering:
const Component = React.Component;
class App extends Component {
state = {
page:0
}
handlePage = () => {
this.setState({
page:1
})
}
render() {
let Comp = null;
if(this.state.page === 1){
Comp = <Page1/>
} else if(this.state.page === 0) {
Comp = <StartPage handlePage={this.handlePage} />
}
return (
<div className="App">
{Comp}
</div>
);
}
}
function StartPage(props) {
return (
<div>
<h1>Let's get started!!</h1>
<div className="button">
<button
type="submit"
onClick={props.handlePage}
>GO</button>
</div>
</div>
);
}
class Page1 extends Component {
render() {
return (
<div className="App">
<h1>Page 1</h1>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
If you have more pages to display, I would encourage you to look at solution like React Router

React - Get the component name in functional components

I want on every component in my app to add attribute component-name="componentX". I don't want to do it hard coded when creating a component but to find a generic way to find the component name and set it in the attribute.
I know there is the displayName property but it's only for class component.
I have a lot of functional components. How can I achieve it?
Thanks!
If you wrap children you can access the child.type.name to get the component / function name.
Here is a small example:
class LogNames extends React.Component {
render() {
const { children } = this.props;
React.Children.forEach(children,child =>{
console.log(child.type.name)
});
return children;
}
}
class Child extends React.Component {
render() {
return <div>A Child</div>
}
}
const Child2 = () => <div>Child 2</div>
class App extends React.Component {
render() {
return (
<div>
<LogNames>
<Child/>
</LogNames>
<LogNames>
<Child2 />
</LogNames>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />
Just noticed you want to set an attribute on the DOM as well, so i added another example that does just that (open devtools to see the attributes):
class WithNameAttr extends React.Component {
componentDidMount(){
const {children} = this.props;
// get a ref to the current node
const node = ReactDOM.findDOMNode(this);
// force and return a signle child
const child = React.Children.only(children);
// set name attribute (if available)
const name = child.type.name;
name && node.setAttribute('component-name', name);
}
render() {
return this.props.children;
}
}
class Child extends React.Component {
render() {
return <div>A Child</div>
}
}
const Child2 = () => <div>Child 2</div>
class App extends React.Component {
render() {
return (
<div>
<WithNameAttr>
<Child />
</WithNameAttr>
<WithNameAttr>
<Child2 />
</WithNameAttr>
<WithNameAttr>
<div>dom elemetns doesnt have names</div>
</WithNameAttr>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>

How to change display onclick in React?

I am wondering how to change a display few elements from hide to visible in React. I have 4 section and for each section button. Start section has start button, About section has about button, Skills section has skills button and Contact section has contact button. How to make it when im clicking Start all others sections get instantly display: none and only Skills section is visible? By clicking About button, others get hide (none) and only About is visible? Etc to others sections.
I know that i have to make a handleonclick but idk how.
Should it work with state?
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Start extends Component {
render() {
return (
<div className='start'>
</div>
);
}
}
class About extends Component {
render() {
return (
<div className='about'>
</div>
);
}
}
class Skills extends Component {
render() {
return (
<div className='skills'>
</div>
);
}
}
class Contact extends Component {
render() {
return (
<div className='contact'>
</div>
);
}
}
class Buttons extends Component {
render() {
return (
<div className="buttons">
<button>Start</button>
<button>About</button>
<button>Skills</button>
<button>Contact</button>
</div>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Buttons />
<Main />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Keep a state activeSection in the parent container called App. Then, pass it as a props to the child section components, About, Skills etc. Also add a method handleToggleSection, which you can call on click to the buttons and change the state activeSection to that corresponding section name. Inside all section components, About, Skills etc., check the current section name. If the name matches, then return the html or return null. Remember, when you return null, that component don't mount. If you want to keep the components mount regardless they are visible or not, then u need to use css classes like show, hide etc.
Here is the demo.
// import React from "react";
// import ReactDOM from "react-dom";
class Start extends React.Component {
get show() {
return this.props.activeSection === "start";
}
render() {
if (this.show) {
return <div className="start"> Start </div>;
} else {
return null;
}
}
}
class About extends React.Component {
get show() {
return this.props.activeSection === "about";
}
render() {
if (this.show) {
return <div className="about"> About </div>;
} else {
return null;
}
}
}
class Skills extends React.Component {
get show() {
return this.props.activeSection === "skills";
}
render() {
if (this.show) {
return <div className="skills"> Skills </div>;
} else {
return null;
}
}
}
class Contact extends React.Component {
get show() {
return this.props.activeSection === "contact";
}
render() {
if (this.show) {
return <div className="contact"> Contact </div>;
} else {
return null;
}
}
}
const Buttons = ({ onToggle }) => (
<div className="buttons">
<button name="start" onClick={onToggle}>
Start
</button>
<button name="about" onClick={onToggle}>
About
</button>
<button name="skills" onClick={onToggle}>
Skills
</button>
<button name="contact" onClick={onToggle}>
Contact
</button>
</div>
);
const Main = ({ activeSection }) => (
<React.Fragment>
<Start activeSection={activeSection} />
<About activeSection={activeSection} />
<Skills activeSection={activeSection} />
<Contact activeSection={activeSection} />
</React.Fragment>
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
activeSection: ""
};
this.handleToggleSection = this.handleToggleSection.bind(this);
}
handleToggleSection(e) {
const { name } = e.target;
this.setState(() => ({
activeSection: name
}));
}
render() {
return (
<div className="App">
<Buttons onToggle={this.handleToggleSection} />
<Main activeSection={this.state.activeSection} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
.App {
font-family: sans-serif;
text-align: center;
}
.show {
display: block;
}
.hide {
display: none;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can use conditional rendering.
selectSection = section => {
this.setState({ section })
}
render() {
return (
<div className="App">
<Buttons onClick={this.selectSection} />
{this.state.section === "start" && <Start>}
{this.state.section === "about" && <About>}
</div>
);
}
Also, instead of the if you can use switch.

Resources