0

This React-Redux code was used to load more content from database each time Loadmore button was clicked and it work fine.

Initial content display was 2 and as you click on loadmore button, more records gets loaded in two's.

I Later find out that each time I click Load more button and more content gets loaded, as I logout and login again those records that was loaded on button click will still be on the Page and therefore causing records display (id) conflicts which results in the following error below

bundle.js:856 Warning: Encountered two children with the same key, 1. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

Please how do I prevent this records display conflicts...

I think what causes this issue is the concatenation of the old/default records with newly loaded records via loadmore button in my user.reducer.js i have the code below

//concatenate the old item with new item

case userConstants.GETALL_REQUEST:
  return {
    ...state,
    loading: true
  };
case userConstants.GETALL_SUCCESS:
  return {
    loading: false,
    error: null,
// items: action.users
    items: [ ...(state.items || []), ...action.users ]
  }; 

here is the homepage components

import React from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";

import { userActions } from "../_actions";

class HomePage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      row_pass: 0
    };
    this.row = 0;
    this.rowperpage = 2;
    this.buttonText = "Load More";
    this.loadMore = this.loadMore.bind(this);
  }

  componentDidMount() {
    this.props.dispatch(userActions.getAll(this.row));
  }

  loadMore() {
    this.row += this.rowperpage;
    alert("loading" + this.row);
    this.props.dispatch(userActions.getAll(this.row));
    this.buttonText = "Load More";
  }




  render() {
    const { user, users } = this.props;
    return (
      <div
        style={{ background: "red" }}
        className="well col-md-6 col-md-offset-3"
      >
        <h1>
          Hi{user.message}! {user.token}
        </h1>
        <p>You're logged in with React!!</p>
        <h3>All registered users:</h3>
        {users.loading && <em>Loading users...</em>}
        {users.error && (
          <span className="text-danger">ERROR: {users.error}</span>
        )}
        {users.items && (
          <ul>
            {users.items.map((user, index) => (
              <li key={user.id}>
                {user.firstName + " " + user.lastName}:
                <span>
                  {" "}
                  - <a>home</a>
                </span>
              </li>
            ))}
            {this.finished}
          </ul>
        )}
        <p>
          <a className="pic" onClick={this.loadMore}>
            {this.buttonText}
          </a>
        </p>
      </div>
    );
  }
}

function mapStateToProps(state) {
  const { users, authentication } = state;
  const { user } = authentication;
  return {
    user,
    users
  };
}

const connectedHomePage = connect(mapStateToProps)(HomePage);
export { connectedHomePage as HomePage };

here is user.action.js

function getAll(row) {
    return dispatch => {
        dispatch(request(row));

        userService.getAll(row)
            .then(
                users => dispatch(success(users)),
                error => dispatch(failure(error.toString()))
            );
    };

user.reducer.js code

import { userConstants } from '../_constants';

export function users(state = {}, action) {
  switch (action.type) {

//concatenate the old item with new item

case userConstants.GETALL_REQUEST:
  return {
    ...state,
    loading: true
  };
case userConstants.GETALL_SUCCESS:
  return {
    loading: false,
    error: null,
// items: action.users
    items: [ ...(state.items || []), ...action.users ]
  };

    case userConstants.GETALL_FAILURE:
      return { 
        error: action.error
      };


    default:
      return state
  }
}
jmarkatti
  • 621
  • 8
  • 29

1 Answers1

2

I think that the best approach to this problem is to reset the redux store when logging out.

I'm saying that because this error message ins't the only problem you have. You are probably displaying duplicated users in the screen. Another problem you might have is if the user that logs in isn't the same that logs out, so is this case you will show the data of one user to another, but maybe this is not a problem for your application, it's up to you evaluate.

If you want to reset the store when the user logs out I recommend you to read this another answer.

If you don't want to do that I imagine 2 workarounds.

  • The first is reseting these users in componentDidMount before you load the initial users.

    To do that you will need something like this in your reducer

    case userConstants.RESET:
      return {
        loading: false,
        error: null,
        items: []
      };
    

    and also have an action that matches this. After that just dispatch that action from componentDidMount with something like this.props.dispatch(userActions.reset());

  • The second workaround is to set the row property based in users quantity in constructor with something like this.row = props.users.items.length;

Just remembering, I suggest that you go with the first solution reseting the entire store when logging out

Rafael Lebre
  • 576
  • 1
  • 8
  • 16
  • Hi Rafael. The link you sent worked for me and it clears the state as user login and logout. please do you know how i can clear those records in componentDidMount as you stated. I have tried componentDidMount() { this.props.clearState(); } but it shows error this.props.clearState() is not a function. btw thanks so far – jmarkatti Nov 05 '18 at 07:24
  • @jmarkatti I edited the answer to show you how to do that and also change the second workaround that I realized that could be better. – Rafael Lebre Nov 05 '18 at 16:19
  • @jmarkatti just for curiosity, do you think that this reset in logout that you mentioned that worked it's not the best for your case? – Rafael Lebre Nov 05 '18 at 16:20
  • You are the best Rafael. God bless You and Stackoverflow at large – jmarkatti Nov 05 '18 at 20:15