3

EDIT I need to sort team cards alphabetically inside my Container component with a button. At the moment the code sorts alphabetically without the button being pressed since I have the sorting logic being mapped to state. Syntax wise, how should I have it only sort when button is clicked and where should the sorting itself be done here?

I have previously had the sorting being done using a reducer case and an action but now want to do it without using actions or reducers and just using React.

Container which displays the Cards:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';

import TeamCard from '../components/TeamCard'
import { displayObject } from '../actions/dataActions'

import CardColumns from 'react-bootstrap/CardColumns'

class DataContainer extends Component {
  state = {
    teamCards: [...this.props.teams.cards]
  };

  sortTeamCards = () => {
    this.setState(prevState => ({
      teamCards: [...prevState.teamCards].sort(function(team1, team2) {
        if (team1.name < team2.name) {
          return -1;
        }
        if (team1.name > team2.name) {
          return 1;
        }
        return 0;
      }),
    }))
  }

  displayCards = () => {
      switch(this.props.path) {
          case "teams":
              return (this.props.teams.cards.map(card => (
                  <NavLink style={{ color: "black" }} to={`/teams/${card.id}`} key={card.id}><TeamCard view={this.props.displayObject} info={card} /></NavLink>
              )));

          default:
              return (<div>Empty</div>)
      }
  };

  render() {
      return (
          <CardColumns>
              <button id="sort-button" title="Sort Teams" onClick={this.sortTeamCards}>Sort Teams</button>
              {this.displayCards()}
          </CardColumns>
        )
     }
  }

  const mapStateToProps = state => {
      return {
          teamCards: state.teams,
          teams: state.teams
      }
  };

  const mapDispatchToProps = dispatch => {
      return {
          displayObject: (id, category, type) => dispatch(displayObject(id, category, type)),
      }
  };

  export default connect(mapStateToProps, mapDispatchToProps)(DataContainer)
12
  • Is handleTeamSort not correctly sorting/updating component state? Is the button's onClick handler not calling handleTeamSort? The two buttons aren't rerendering? (They don't change depending on state so when they do rerender they look the same) Seems there's an implied question in there somewhere. How does TeamFilter relate to DataContainer? Commented Mar 16, 2020 at 3:37
  • handleTeamSort is not sorting. The button's onClick is calling as I tested with console log. TeamFilter was initially just for fetching teams and displaying them (which works fine) and it doesn't directly relate to DataContainer but the mapping of the team cards in DataContainer might be related to this issue I thought. Data Container is basically for displaying the teams in the card structure and allowing to navigate to the individual team card's id. Commented Mar 16, 2020 at 4:31
  • I may be assuming, but is fetchTeams connected to your component? I see it referenced within as this.props.fetchTeams. What does that action ultimately do? Presumably populate something into this.state.teams? Far as I can tell from what is shared, this.state.teams is an empty array. Commented Mar 16, 2020 at 5:23
  • I think I should make this button and the sorting in the Container since it is where the rendering of the cards is happening. The teams are in the store alraedy so I just need to figure out how to implement the sort for the displayCards function to use. Commented Mar 16, 2020 at 21:41
  • Do you want the sorting to be permanent, i.e. click a button and the data in redux state gets sorted? or sort only what is displayed after a button click, i.e. reload the page and the data goes back to unsorted? Commented Mar 17, 2020 at 2:58

2 Answers 2

1

Seems you want to maintain a "local" copy of your team cards array and selectively sort that array, leaving the source of truth in your redux state maintained/intact.

You'll simply need a component state variable to hold the unsorted or sorted array for display.

Here is a very distilled down version:

const teamSortFn = (team1, team2) => {
  if (team1.name < team2.name) {
    return -1;
  }
  if (team1.name > team2.name) {
    return 1;
  }
  return 0;
}

class DataContainer extends Component {
  state = {
    // copy props to state to play with and not mutate external refs
    teamCards: [...this.props.teams.cards],
  };

  ...

  sortTeamCards = () => {
    this.setState(prevState => ({
      teamCards: [...prevState.teamCards].sort(teamSortFn),
    }))
  }

  ...

  render() {
    return (
      <CardColumns>
        <button
          id="sort-button"
          title="Sort Teams"
          onClick={this.sortTeamCards}
        >
          Sort Teams
        </button>
        {this.displayCards()}
      </CardColumns>
    );
  }
}

Edit goofy-mestorf-kx3ew

Sign up to request clarification or add additional context in comments.

8 Comments

it doesn't seem to be sorting the team cards on button click and doesn't render the teams. Could it be that the sorting should be done only after the TeamFilter Component's show teams button be clicked? The sandbox example has the data rendered already as well.
What's the TeamFilter component? The sandbox demo has the UI abstracted away so it's easier to focus on the state updates that occur in order to save a local temp copy of some data in an array and how to sort it in an event handler. How the data gets passed to your UI component is up to you. In your example you pass it in on the teams prop via the connect HOC. If your teams prop can mutate over time then you'll need to also leverage the componentDidUpdate to "reset" the local state to the "new" teams array (to be sorted on next sort button click).
So I need to reset the local state with the sorted teams on button click using componentDidUpdate? Syntax wise it should be as in the sandbox demo? Basically my app can have the teams being rendered normally (in the order they are in the database) when clicking the show teams button in my TeamFilter component. And it should render the teams in a sorted order when the sort button is clicked (which is located in this DataContainer).
IDK, I'm just guessing since you added new details. If I understand you now, you want to display an array of data, with two buttons that sort your data each differently, and you want to be able to toggle between them?
Right now I have a show all teams button which works and displays all my team cards. But prior to clicking it I have no teams being shown. I was thinking if the sort button I added should do the same thing but already sorted or should my show team button have to be clicked first and only then do I have the option of clicking the sort button to sort the teams.
|
0

Ok I modified my container to this and it seems to have fixed the button.

import React, { Component, Fragment } from "react";
import { connect } from "react-redux";
import { NavLink } from "react-router-dom";

import TeamCard from "../components/TeamCard";
import PlayerCard from "../components/PlayerCard";
import StarPlayerCard from "../components/StarPlayerCard";
import { displayObject } from "../actions/dataActions";

import CardColumns from "react-bootstrap/CardColumns";

class DataContainer extends Component {
  state = {
    teams: this.props.sort_teams
  };

   sortTeams = () => {
    this.props.sort_teams.cards.sort(function(team1, team2) {
        if (team1.name < team2.name) {
          return -1;
        }
        if (team1.name > team2.name) {
          return 1;
        }
        return 0;
      });
      this.setState({
        teams: this.props.sort_teams
      });
  };

  displayCards = () => {
      switch(this.props.path) {
          case "teams":
              return (this.props.teams.cards.map(card => (
                  <NavLink style={{ color: "black" }} to={`/teams/${card.id}`} key={card.id}><TeamCard view={this.props.displayObject} info={card} /></NavLink>
              )));

          case "players":
              return (this.props.players.cards.map(card => (
                  <NavLink style={{ color: "black" }} to={`/players/${card.id}`} key={card.id}><PlayerCard view={this.props.displayObject} info={card} /></NavLink>
              )));

          case "star_players":
              return (this.props.star_players.cards.map(card => (
                  <NavLink style={{ color: "black" }} to={`/star_players/${card.id}`} key={card.id}><StarPlayerCard view={this.props.displayObject} info={card} /></NavLink>
              )));

          default:
              return (<div>Empty</div>)
      }
  };

  render() {
      return (
        <Fragment>
          <div>
            <button id="sort-button" title="Sort Teams" onClick={this.sortTeams}>Sort Teams</button>
          </div>
          <CardColumns>{this.displayCards()}</CardColumns>
        </Fragment>
      );
    }
  }

  const mapStateToProps = state => {
      return {
          sort_teams: state.teams,
          teams: state.teams,
          players: state.players,
          star_players: state.star_players
        }
    };

    const mapDispatchToProps = dispatch => {
        return {
            displayObject: (id, category, type) => dispatch(displayObject(id, category, type)),
        }
    };

export default connect(mapStateToProps, mapDispatchToProps)(DataContainer)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.