0

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>
        );
      });
  }
6
  • can you be a little more specific on how you implement your keys? Commented Oct 4, 2017 at 8:45
  • I'm guessing you're not changing your state so react doesn't know it needs to update the UI. Check out this question and maybe try forceUpdate(), or sort the values and store the result in your state. Commented Oct 4, 2017 at 8:46
  • @EnriqueDev My sortKey hasn't been fully implemented yet. I am getting my keys in a JSON object from an action creator using redux. this.props.fetchSurveys(); Commented Oct 4, 2017 at 9:01
  • any improvements? Commented Oct 4, 2017 at 10:05
  • @EnriqueDev I stored my state on the lifecycle hook, but I'm unsure how I should call sortList() correctly. It says "," expected the array.sort() call. Commented Oct 4, 2017 at 10:29

2 Answers 2

1

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.

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

2 Comments

I am getting my data from an API on my backend, using an action creator with redux. When the component loads, the action to fetch the data is invoked and the state is mapped to the component properties.
Rather than explaining every step of your code please add more complete example of it. Without knowing how you render your list or how and where you implement sort it hard to give a good answer.
1

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.

1 Comment

Thanks for your answer. What do you mean by storing the votes on state? How would i update the state after the sort?

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.