David Trinh
David Trinh

Reputation: 329

previous state is rendering (duplicate) with new state

I am having trouble figuring out why my component renders both the previous prop and the new prop instead of only the diff.

For example it renders:

[[1, 2, 3, 4, 5]]
[[6, 7, 8, 9, 10]]
[[1, 2, 3, 4, 5]]
[[6, 7, 8, 9, 10]]
[[16, 57, 8, 19, 5]]

Instead of just:

[[1, 2, 3, 4, 5]]
[[6, 7, 8, 9, 10]]
[[16, 57, 8, 19, 5]]

My main component:

class AsyncApp extends Component {
  constructor(props) {
    super(props)
  }

  lookForUpdate() {
    // this function hits a endpoint every 10 sec.
    setInterval(() => {
      this.props.dispatch(fetchDataForReals())
      }, 10000)
  }

  componentDidMount() {
    this.props.dispatch(fetchDataForReals())
    this.lookForUpdate()
  }

  render() {
    const { graphData } = this.props;

    return (
      <div>
        <div>hello</div>
        <DataGraph graphData={graphData} />
      </div>
    )
  }
}

function mapStateToProps(state) {
  let graphData = state.payment.graphDatas
  return {
    graphData
  }
}

export default connect(mapStateToProps)(AsyncApp)

My other component:

import React, { Component } from 'react'

export default class DataGraph extends Component {
  constructor(props) {
    super(props)
  }

  shouldComponentUpdate(nextProps) {
    return nextProps.graphData !== this.props.graphData
  }

  render() {
    return (
      <div>{this.props.graphData.map(function(datas){
        return datas.map(function(data, index){
           return <li key={index}>{data.series}</li>
        })
      })}</div>
    )
  }
}

export default DataGraph;

My action.js

function requestDataArray() {
  return {
    type: REQUEST_DATA
  }
}

function recieveDataArray(data) {
  return {
    type: RECIEVE_DATA,
    data: data.map(child => child),
    receivedAt: Date.now()
  }
}


function fetchData() {
  return dispatch => {
    dispatch(requestDataArray())
    return fetch('//localhost:3000/api/v1/data', {
      mode: 'no-cors'
    }).then(function(data){
      return data.json()
    }).then(function(data){
      dispatch(recieveDataArray(data))
    })
  }
}

export function fetchDataForReals() {
  return (dispatch) => {
    return dispatch(fetchData())
  }
}

My reducers:

const initialState = {
  graphDatas: [],
  friendsList : {},
  comments: []
}

function addData(state = initialState.graphDatas, action) {
  switch(action.type) {
    case 'RECIEVE_DATA':
      var clone = _.cloneDeep(state);
      var resultPopOff = clone.pop()
      let stateResult = _.isEqual(resultPopOff, action.data)
      if (stateResult) {
        return state
      } else {
        return [
          ...state, action.data
        ]
      }
    default:
      return state;
  }
}

const payment = (state = initialState, action) => {
  switch(action.type) {
    default:
      return {
        graphDatas: addData(state.graphDatas, action)
      }
  }
}

const rootReducer = combineReducers({
  payment, routing: routerReducer
})

export default rootReducer

Upvotes: 1

Views: 945

Answers (1)

David Gilbertson
David Gilbertson

Reputation: 4863

I think where you're doing this in your reducer:

return [
  ...state, action.data
]

You should be returning the clone that you pop()ed off:

return [
  ...clone, action.data
]

Upvotes: 1

Related Questions