0

I am passing a list of articles via const ARTICLES from index.js to App.js

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import { applyPolyfills, defineCustomElements } from "h8k-components/loader";

const ARTICLES = [
  {
    title: "A message to our customers",
    upvotes: 12,
    date: "2020-01-24",
  },
  {
    title: "Alphabet earnings",
    upvotes: 22,
    date: "2019-11-23",
  },
  {
    title: "Artificial Mountains",
    upvotes: 2,
    date: "2019-11-22",
  },
  {
    title: "Scaling to 100k Users",
    upvotes: 72,
    date: "2019-01-21",
  },
  {
    title: "the Emu War",
    upvotes: 24,
    date: "2019-10-21",
  },
  {
    title: "What's SAP",
    upvotes: 1,
    date: "2019-11-21",
  },
  {
    title: "Simple text editor has 15k monthly users",
    upvotes: 7,
    date: "2010-12-31",
  },
];

ReactDOM.render(<App articles={ARTICLES} />, document.getElementById("root"));
registerServiceWorker();

applyPolyfills().then(() => {
  defineCustomElements(window);
});

I then pass the same list of articles from App.js to components/Article.js using React Hooks to update the order of the articles based on their upvotes and date properties when their respective buttons are clicked. But the update never happens. I can see the articleList changes when the buttons are clicked via console.log, but the Article.js component does not re-render these changes.

import React, { useState } from "react";
import "./App.css";
import "h8k-components";

import Articles from "./components/Articles";

const title = "Sorting Articles";

function App({ articles }) {
  const [articleList, setArticle] = useState(articles);

  function onTopClicked() {
    setArticle(
      articleList.sort(function (a, b) {
        return b.upvotes - a.upvotes;
      })
    );
    console.log("top", articleList);
  }

  function onNewestClicked() {
    setArticle(
      articleList.sort(function (a, b) {
        let dateA = new Date(a.date);
        let dateB = new Date(b.date);
        return dateB - dateA;
      })
    );
    console.log("date", articleList);
  }

  return (
    <div className="App">
      <h8k-navbar header={title}></h8k-navbar>
      <div className="layout-row align-items-center justify-content-center my-20 navigation">
        <label className="form-hint mb-0 text-uppercase font-weight-light">
          Sort By
        </label>
        <button
          data-testid="most-upvoted-link"
          onClick={onTopClicked}
          className="small"
        >
          Most Upvoted
        </button>
        <button
          onClick={onNewestClicked}
          data-testid="most-recent-link"
          className="small"
        >
          Most Recent
        </button>
      </div>
      <Articles articles={articleList} />
    </div>
  );
}

export default App;

The Article.js component receives the articleList data via its props.

import React from "react";

function Articles({ articles }) {
  return (
    <div className="card w-50 mx-auto">
      <table>
        <thead>
          <tr>
            <th>Title</th>
            <th>Upvotes</th>
            <th>Date</th>
          </tr>
        </thead>
        <tbody>
          {articles.map((article, i) => (
            <tr key={i} data-testid="article" key="article-index">
              <td data-testid="article-title">{article.title}</td>
              <td data-testid="article-upvotes">{article.upvotes}</td>
              <td data-testid="article-date">{article.date}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

export default Articles;

Why won't the articles re-render the articleList data when the buttons from App.js are clicked so I can re-order my articles based on their upvotes and date properties?

1 Answer 1

2

The sort function does not create return a new array. It sorts in place and returns the same array. So the reference is still the same and the state is not updated.

You should make a copy of the sorted array and set it as a new state

    setArticle(
      [...articleList.sort(function (a, b) {
        let dateA = new Date(a.date);
        let dateB = new Date(b.date);
        return dateB - dateA;
      })]
    );
Sign up to request clarification or add additional context in comments.

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.