Leth
Leth

Reputation: 1059

Change sort key for rendered mapped array in React

I want to have client side sorting that enables the user to sort by different keys. The keys are integers only.

Right now I am calling my sort function right before the map function:

.sort(function(a, b) {
        return b.sortKey- a.sortKey;
      }

When the user presses a button, the sortKey should change to a specified value. This is all included in a react component, not a function. I read that properties on a component should not be changed by the component itself, so how would i go about changing the sortKey on the button press?

My render function contains the two sorting options and the list:

render() {
    return (
      <div className="row">
        <div className="col s12">
          <button onClick={() => this.changeSortKey("yes")} style={{ marginRight: 5, marginTop: 5 }} className="btn">
            Yes Votes
          </button>
          <button onClick={() => this.changeSortKey("no")} style={{ marginTop: 5 }} className="btn">
            No Votes
          </button>
        </div>

        {this.renderSurveys()}
      </div>
    );
  }

The changeSortKey(key) function would ideally change the sortKey and then render the list anew, but I'm not sure how to render the list again, after the user has clicked.

If i just supply the sort function with a known key, the sorting works perfectly.

EDIT: Fetching the data from API

export const fetchSurveys = () => async dispatch => {
  const response = await axios.get("/api/surveys");
  dispatch({ type: FETCH_SURVEYS, payload: response.data });
};

EDIT: RenderSurveys helper function

renderSurveys() {
    //custom helper method
    return this.props.surveys
      .sort(function(a, b) {
        return b.yes - a.yes;
      })
      .map(survey => {
        const data = [
          { text: "Yes", value: survey.yes },
          { text: "No", value: survey.no }
        ];
        //reverse the array and then map over it, newest first
        return (
          <div className="col s6">
            <div key={survey._id} className="card darken-1">
              <div className="card-content">
                <span className="card-title">{survey.title}</span>
                <p>Sent On: {new Date(survey.dateSent).toLocaleDateString()}</p>
                <p>
                  Last responded on:{" "}
                  {new Date(survey.lastResponded).toLocaleDateString()}
                </p>
              </div>

              <div className="card-action">
                <a href="#">Yes: {survey.yes}</a>
                <a href="#">No: {survey.no}</a>
                <BarChart width={100} height={70} data={data} />
                <button
                  onClick={() => this.props.deleteSurvey(survey._id)}
                  className="btn-floating btn-large red right"
                >
                  <i className="material-icons">clear</i>
                </button>
              </div>
            </div>
          </div>
        );
      });
  }

Upvotes: 0

Views: 2682

Answers (2)

EnriqueDev
EnriqueDev

Reputation: 1247

I would do as follows:

  1. First, on your componentWillMount method I would store your votes on state.

  2. Then, when your user clicks the button, store the votes value on a let variable and sort that variable.

  3. Finally, update your state with the new sorted array.

This way your component will re render every time you sort your array:

componentWillMount() {
  this.setState({ myArray: this.props.yourReduxStoredProp });
}

_sortList() => {
  // retrieve your array from state
  let myArray = this.state.myArray;

  // sort the array locally
  myArray.sort(function(a, b) {
    return b.sortKey- a.sortKey;
  });

  // update the state and, because of the change it state, the component re-renders
  this.setState({ myArray: myArray });
}

Remember that Redux becomes handy when you have to share data between many views, but if you are just showing data in a single view it is way more usefull to use the component state.

I would use redux to store de values on the long term and keep them stored in your app, but the state to manipulate the display of that data.

Upvotes: 1

bennygenel
bennygenel

Reputation: 24660

If you store the sorted version of your data in state, when you re-sorted and then set it to the state the component will be rendered with the new sorted array.

Upvotes: 1

Related Questions