alpesh solanki
alpesh solanki

Reputation: 21

My prevProps and current props in componentDidUpdate are coming same, while I am updating the state

I have added sorting facility in my table. While I sort or delete an element, 2 arrays are coming same, one of prevprops and another of current props. I reviewed my code and found error coming from following piece of code.

Here is my Pagination.js code

import React from "react"

const propTypes = {
    // items: React.PropTypes.array.isRequired,
    // onChangePage: React.PropTypes.func.isRequired,
    // initialPage: React.PropTypes.number    
}

const defaultProps = {
    initialPage: 1
}

class Pagination extends React.Component {
    constructor(props) {
        super(props);
        this.state = { pager: {} };
    }

    componentWillMount() {
        //set page if items array isn't empty
        if (this.props.items && this.props.items.length) {
            this.setPage(this.props.initialPage);
     }
  }

    // componentDidUpdate(prevProps,prevState) {

    //     if (this.props.items !== prevProps.items) {
    //         this.setPage(this.props.initialPage);     
    //     }



    // }
    componentWillReceiveProps (newProps) {
          if (this.props.items !== newProps.items) {
            this.setPage(this.props.initialPage);     
        }  
    }

    setPage(page) {

        var items = this.props.items;
        var pager = this.state.pager;
        if (page < 1 || page > pager.totalPages) {
            return;
        }
        // get new pager object for specified page
        pager = this.getPager(items.length, page);


        // get new page of items from items array
        var pageOfItems = items.slice(pager.startIndex, pager.endIndex + 1);

        // update state
        this.setState({ pager: pager });

        // call change page function in parent component

        this.props.onChangePage(pageOfItems);

    }

    getPager(totalItems, currentPage, pageSize) {
        // default to first page
        currentPage = currentPage || 1;

        // default page size is 10
        pageSize = pageSize || 10;

        // calculate total pages
        var totalPages = Math.ceil(totalItems / pageSize);

        var startPage, endPage;
        if (totalPages <= 10) {
            // less than 10 total pages so show all
            startPage = 1;
            endPage = totalPages;
        } else {
            // more than 10 total pages so calculate start and end pages
            if (currentPage <= 6) {
                startPage = 1;
                endPage = 10;
            } else if (currentPage + 4 >= totalPages) {
                startPage = totalPages - 9;
                endPage = totalPages;
            } else {
                startPage = currentPage - 5;
                endPage = currentPage + 4;
            }

        }

        // calculate start and end item indexes
        var startIndex = (currentPage - 1) * pageSize;
        var endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);

        // create an array of pages to ng-repeat in the pager control
        var pages = [...Array((endPage + 1) - startPage).keys()].map(i => startPage + i);

        // return object with all pager properties required by the view
        return {
            totalItems: totalItems,
            currentPage: currentPage,
            pageSize: pageSize,
            totalPages: totalPages,
            startPage: startPage,
            endPage: endPage,
            startIndex: startIndex,
            endIndex: endIndex,
            pages: pages
        };
    }

    render() { 

        var pager = this.state.pager;

        if (!pager.pages || pager.pages.length <= 1) {
            // don't display pager if there is only 1 page
            return null;
        }

        return (
            <ul className="pagination">
                <li className={pager.currentPage === 1 ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(1)}>First</a></li>
                <li className={pager.currentPage === 1 ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(pager.currentPage - 1)}>Previous</a>
                </li>
                {pager.pages.map((page, index) =>
                <li key={index} className={pager.currentPage === page ? 'active' : ''}>
                    <a onClick={() => this.setPage(page)}>{page}</a>
                </li>
                )}
                <li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(pager.currentPage + 1)}>Next</a>
                </li>
                <li className={pager.currentPage === pager.totalPages ? 'disabled' : ''}>
                    <a onClick={() => this.setPage(pager.totalPages)}>Last</a>
                </li>
            </ul>
        );
    }
}

Pagination.propTypes = propTypes;
Pagination.defaultProps = defaultProps;

export default Pagination

Here is my App.js code

import React from 'react';
import "./App.css"
import Table from "./components/table"
import SearchBar from "./components/search"
import "antd/dist/antd.css";
import data from "./data"
import Pagination from "./components/pagination"

export default class App extends React.Component {
constructor(props){   
  super(props);
  // var exampleItems = [...Array(150).keys()].map(i => ({ id: (i+1), name: 'Item ' + (i+1) }))
  this.state={  
   filterText:"",
    // products:data,
    // currentPage: 1,
    // todosPerPage: 3,
    exampleItems:data,  
    pageOfItems: [],  
  }
  this.onChangePage = this.onChangePage.bind(this);
  this.handleRowDel = this.handleRowDel.bind(this)
}
// componentWillMount(){
//this.setState({exampleItems: this.state.products})
// }

onChangePage(pageOfItems) {
  // update state with new page of items
  this.setState({ pageOfItems: pageOfItems });

}

handleUserInput = (filterText) => {
  this.setState({filterText:filterText})  
}

handleProductTable = (evt) => {

  let item = {
    id: evt.target.id,
    name: evt.target.name,
    value: evt.target.value
  };

  let products = this.state.exampleItems;

  let newProducts = products.map(function(product) {

    Object.keys(product).forEach(key => {
      // eslint-disable-next-line
      if (key == item.name && product.id == item.id) {      
             product[key] = item.value;
           }
    })

    // for (var key in product) {
    //   // eslint-disable-next-line
    //   console.log(key);
    //   if (key == item.name && product.id == item.id) {      
    //     product[key] = item.value;
    //   }
    // }

    return product;
  });
  this.setState({exampleItems:newProducts});
};

async handleRowDel (product){
  const { exampleItems } = this.state;
  let index = exampleItems.indexOf(product);
  exampleItems.splice(index, 1);
 await this.setState({exampleItems:exampleItems}); 

};

handleAddEvent = (one,two,three,four) =>{
  let products= this.state.exampleItems;
  let count = + new Date();
  let item={
    id: count,
    name: one,
    price: two,
    qty: three,
    category: four,
  }
  products.push(item);
  this.setState({exampleItems:products}); 
}

orderChange = (e) =>{
  var  trimText = e.substr(4);
  var  arrangeMethod = e.substr(0,3);
  if(trimText === "price" || trimText === "qty") {
    this.arrangeNumber(trimText, arrangeMethod);
  }
  if(trimText === "category"){
    this.arrangeText(trimText,arrangeMethod);
  }

}

arrangeNumber = (key,arrangeMethod) =>{
  let arraycopy = this.state.exampleItems;
  if(arrangeMethod === "asc"){
    arraycopy.sort(function(a,b){
      if(Number(a[key]) < Number(b[key])){ return -1;}
      if(Number(a[key]) > Number(b[key])){ return 1;}
      return 0
    })
  }
  if(arrangeMethod === "des"){
    arraycopy.sort(function(a,b){
      if(Number(a[key]) > Number(b[key])){ return -1;}
      if(Number(a[key]) < Number(b[key])){ return 1;}
      return 0
    })
  }

 this.setState({exampleItems:arraycopy});

}
arrangeText = (key,arrangeMethod) =>{
  let arraycopy = this.state.exampleItems;
  if(arrangeMethod === "asc"){
    arraycopy.sort(function(a,b){
      if((a[key]) < (b[key])){ return -1;}
      if((a[key]) > (b[key])){ return 1;}
      return 0
    })
  }
  if(arrangeMethod === "des"){
    arraycopy.sort(function(a,b){
      if((a[key]) > (b[key])){ return -1;}
      if((a[key]) < (b[key])){ return 1;}
      return 0
    })
  }

 this.setState({exampleItems:arraycopy});
}

handleClick = (event) =>{
  this.setState({
    currentPage: Number(event.target.id)
  });
}

  render(){

    // const { currentPage, todosPerPage,products } = this.state;
    // // Logic for displaying current todos
    // const indexOfLastTodo = currentPage * todosPerPage;
    // const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
    // console.log(products.slice(indexOfFirstTodo,indexOfLastTodo));
    // const currentTodos = products.slice(indexOfFirstTodo, indexOfLastTodo);
    // const renderTodos = currentTodos.map((todo, index) => {
    //   return <li key={index}>{todo}</li>;
    //    });  
    // const pageNumbers = [];
    //   for (let i = 1; i <= Math.ceil(products.length / todosPerPage); i++) {
    //     pageNumbers.push(i);
    //   }
    // const renderPageNumbers = pageNumbers.map(number => {
    //     return (
    //       <li
    //         key={number}
    //         id={number}
    //         onClick={this.handleClick}
    //       >
    //         {number}
    //       </li>
    //     );
    //   });
    return(
      <div>
        {/* <SearchBar 
          filterText={this.state.filterText} 
          onUserInput={this.handleUserInput} 
        />       */

        }
        <Table 
          onProductTableUpdate={this.handleProductTable} 
          onRowAdd={this.handleAddEvent} 
          products={this.state.pageOfItems}
          // currentTodos
          onDelEve={this.handleRowDel}
          filterText={this.state.filterText} 
          orderChange={this.orderChange}
        /><div className="pagination">  
          {/* <ul id="page">
           {renderPageNumbers}
          </ul> */}
      </div>

      <div className="container">
                    <div className="text-center">

                        {/* {this.state.pageOfItems.map(item =>
                            <div key={item.id}>{item.name}</div>
                        )} */ }

                        <Pagination items={this.state.exampleItems} onChangePage={this.onChangePage} />
                    </div>
                </div>



      </div>

    );
  }

}

Can you please tell me, where I should change my code ?

Upvotes: 2

Views: 2643

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 84982

You have several instances where you are mutating the state. In react, your state needs to be immutable, otherwise it's not possible to compare before and after, because before and after are the same thing. For example, you have this code here:

handleAddEvent = (one,two,three,four) => {
  let products = this.state.exampleItems;
  let count = + new Date();
  let item = {
    id: count,
    name: one,
    price: two,
    qty: three,
    category: four,
  }
  products.push(item);
  this.setState({ exampleItems:products }); 
}

You need to make a copy of the state before you start making modifications. For example, replace the first line of the function with:

let products = [...this.state.exampleItems];

Note: You have this issue in multiple places, not just handleAddEvent. I show that function just as an example. You'll probably need to fix all cases where you're mutating state in order to resolve your issue.

Upvotes: 2

Related Questions