skip to Main Content

At the moment the votes {count} is not showing up on mount. I’m using useEffect to get the article and useState to set the count to article.votes. The votes go up after clicking the button twice as the first render doesn’t show the vote count.

const Article = () => {
  const { article_id } = useParams();

  const [article, setArticle] = useState({ title: "Not Found" });

  useEffect(() => {
    getArticle(article_id).then((article) => {
      setArticle(article);
    });
  }, []);

  const [count, setCount] = useState(article.votes);

  function handleCountUp() {
    updateArticleVotes(article_id, count, article.votes);
    setCount(article.votes++);
  }

  function handleCountDown() {
    setCount(article.votes--);
    updateArticleVotes(article_id, count, article.votes);
  }

  const navigate = useNavigate();

  function handleNavigate() {
    navigate("./#form");
  }

  return (
    <div>
      <div className="one-article-div" id="top">
        <h5>Votes: {count}</h5>
        <button
          onClick={handleCountUp}
          name="Vote Up"
          className="input-submit margin-left-right"
        >
          Vote Up
        </button>
        <button
          onClick={handleCountDown}
          name="Vote Down"
          className="input-submit margin-left-right"
        >
          Vote Down
        </button>
      </div>
    </div>
  );
};

export default Article;

I’m expecting the <h5>votes: {count}</h5> to show up on mount. At the moment it only shows up after clicking the up vote or down vote.

3

Answers


  1. At the moment the votes {count} is not showing up on mount

    It would not show up, because here:

      const [count, setCount] = useState(article.votes);
    

    you have initialized count with article.votes.
    Even if you change article.votes to something else afterwards, the count will not be re-initialized. From the docs:

    The value you want the state to be initially. It can be a value of any
    type, but there is a special behavior for functions. This argument is
    ignored after the initial render.

    You have to update count too using setCount, after you get new article in useEffect.

    Login or Signup to reply.
  2. Inside the useEffect you need to add a setCount(article.votes).

    In your case, it doesn’t work because the useEffect run after the mounting of your component. So at that time articles is undefined so votes is also undefined. And the initializer of the count state is set to undefined.

    useEffect(() => {
        getArticle(article_id).then((article) => {
          setArticle(article);
          setCount(article.votes);
        });
      }, []);
    
    Login or Signup to reply.
  3. I’m expecting the votes: {count} to show up on mount.

    It does display/render on the initial render cycle, but the problem is that the initial article state has an undefined votes property.

    const [article, setArticle] = useState({
      title: "Not Found" // no votes property
    });
    const [count, setCount] = useState(article.votes); // undefined
    

    I suggest you provide a default votes property value, and update the effect to also update the count state when it updates the article state. Don’t forget to include the article_id route path parameter as a dependency so the effect also runs if/when the article id parameter value changes.

    const [article, setArticle] = useState({
      title: "Not Found",
      votes: 0,
    });
    const [count, setCount] = useState(article.votes);
    
    useEffect(() => {
      getArticle(article_id)
        .then((article) => {
          setArticle(article);
          setCount(article.votes);
        });
    }, [article_id]);
    

    The vote handlers are also mutating the article state with the post-increment/decrement operators. You should avoid mutating React states. Add or subtract 1 from the current article.votes value and pass that result to the setCount state setter function.

    function handleCountUp() {
      updateArticleVotes(article_id, count, article.votes);
      setCount(article.votes + 1);
    }
    
    function handleCountDown() {
      updateArticleVotes(article_id, count, article.votes);
      setCount(Math.max(0, article.votes - 1));
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search