Sagar
Sagar

Reputation: 1155

Why my render method is react called twice

enter image description hereI am quite new to react and redux. This is a little confusing problem for me. Can someone please explain this why my searchTerm state value printed twice (render method is getting called twice) after every input change. I read react and learnt that on every state change, render is called but in this called render is called twice? Am I getting this wrong?

App.js

import React from 'react';
import Todos from './components/Todos';
import Header from './components/Header';

class App extends React.Component {
state = {
    searchTerm : '',
    todos: [{
    id: 1,
    completed: true,
    text: "I am number one"
    }, 
{
    id: 2,
    completed: false,
    text: "I am number two"
},
{
    id: 3,
    completed: false,
    text: "I am number three"
}]
}

markComplete = (id) => {
    this.setState({
    todos: this.state.todos.map(todo => {
        if (todo.id === id) {
        todo.completed = !todo.completed;
        }
        return todo;
    })
    });
}

deleteTo = (id) => {
    this.setState({
    todos: [...this.state.todos.filter(todo => todo.id!==id)]
    });
}

search = (evt) => {
    const value = evt.target.value;
    this.setState({
    searchTerm: value
    });
}

render() {
    return (
    <div>
        <Header />
        { console.log(this.state.searchTerm) }
        <input type="text" onChange = {this.search} />         
        <Todos todos = {this.state.todos} markComplete = {this.markComplete} deleteTo = {this.deleteTo}/>
    </div>
    );
}
}

export default App;

Todos.js

import React, { Component } from 'react';
import TodoItem from './TodoItem';

class Todos extends Component {

render() {
    return this.props.todos.map((todo) => 
    <TodoItem key={todo.id} todo = {todo} markComplete = {this.props.markComplete} deleteTo={this.props.deleteTo}/>)
}
}

export default Todos;

TodoItem.js

import React, { Component } from 'react';

class TodoItem extends Component {

getStyle = () => {
    return { textDecoration: this.props.todo.completed ? "line-through": "none" };
};

getButtonStyle = () => {
    return {
        backgroundColor: 'red',
        border: 'none',
        cursor: 'pointer',
        float: 'right',
        padding: '5px 10px',
        borderRadius: '50%'
    };
}

render() {
    const {id, text} = this.props.todo;

    return ( 
    <div style={this.getStyle()}>
        <p>
        <input type="checkbox" onChange= { () => this.props.markComplete(id) }/> {' '}
        {text} 
        <button style={this.getButtonStyle()} onClick = { () => this.props.deleteTo(id)}> x </button>
        </p>
    </div>
    );
}
}

export default TodoItem;

Upvotes: 9

Views: 13668

Answers (3)

Kianoosh Sanatkar
Kianoosh Sanatkar

Reputation: 525

it's probably because of React StrictMode in your index.js file (if you use create-react-app).

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
serviceWorker.unregister();

strict mode checks for potential problems and caused to run some lifecycle methods twice (like constructor, render, componentShouldUpdate, etc).

Strict mode checks are run in development mode only; they do not impact the production build.

you can read more about it on strict-mode

Upvotes: 40

Al1
Al1

Reputation: 386

A simple solution to avoid the side effects is to not assign Dynamic values in the Render(), just keep it in the state, and call it before the Render() as example on Click() method.

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 202605

The render function can be called almost any number of times before the commit phase occurs and updates are flushed to the DOM. The render function should also be a pure function, meaning there are no side-effects, like console logging. Instead use the componentDidUpdate lifecycle function to log when state or props update. Perhaps this diagram would help.

enter image description here

Upvotes: 5

Related Questions