skip to Main Content

I’m trying to realize very simple functionality. A user must have a possibility to search posts by its tag. So, I have the following Feed.jsx component:

"use client";

import { useState, useEffect } from "react";

import PostCard from "./PostCard";

const PostCardList = ({ data, handleTagClick }) => {
  return (
    <div className='mt-16 prompt_layout'>
      {data.map((post) => (
        <PostCard
          key={post._id}
          post={post}
          handleTagClick={handleTagClick}
        />
      ))}
    </div>
  );
};

const Feed = () => {
  const [posts, setPosts] = useState([]);

  // Search states
  const [searchText, setSearchText] = useState("");

  const fetchPosts = async () => {
    console.log(`searchText: ${searchText}`);

    let url = '/api/post';
    if (searchText) {
      url = `/api/post/tag/${searchText}`;
    }

    const response = await fetch(url);
    const data = await response.json();

    setPosts(data);
  };

  useEffect(() => {
    fetchPosts();
  }, []);

  const handleSearchChange = (e) => {
    setSearchText(e.target.value);

    if (e.key === "Enter") {
      fetchPosts();
    }
  };

  return (
    <section className='feed'>
      <form className='relative w-full flex-center'>
        <input
          type='text'
          placeholder='Search for a tag or a username'
          value={searchText}
          onChange={handleSearchChange}
          required
          className='search_input peer'
        />
      </form>

      <PostCardList
          data={posts}
          handleTagClick={() => {}}
        />
    </section>
  );
};

export default Feed;

But it doesn’t work. When a user types tag into input and hits Enter, /api/post endpoint invoked instead of /api/post/tag/${searchText}. Console writes the following lines:

searchText: 
searchText: 

ChatGPT suggests that the reason why the /api/post endpoint is always being invoked instead of /api/post/tag/${searchText} when the user hits Enter is because the searchText variable is updated asynchronously. By the time fetchPosts() is called within handleSearchChange(), the searchText value hasn’t been updated yet.

To fix this issue, it modified my code as follows:

const fetchPosts = async (searchQuery) => {
    console.log(`searchQuery: ${searchQuery}`);
    console.log(`searchText: ${searchText}`);

    let url = '/api/post';
    if (searchQuery) {
      url = `/api/post/tag/${searchQuery}`;
    }

    const response = await fetch(url);
    const data = await response.json();

    setPosts(data);
  };

  useEffect(() => {
    fetchPosts();
  }, []);

  const handleSearchChange = (e) => {
    setSearchText(e.target.value);

    if (e.key === "Enter") {
      fetchPosts(e.target.value);
    }
  };

But it doesn’t help. Console writes the following:

searchQuery: undefined
searchText: 
searchQuery: undefined
searchText: 

2

Answers


  1. From docs, onChange is not triggered until the element looses focus.

    I suggest using different event such as onKeyPress, onKeyDown, onKeyUp, etc.

    Login or Signup to reply.
  2. Try this:
    remove this block from handleSearchChange function:

    if (e.key === "Enter") {
          fetchPosts(e.target.value);
    }
    

    Then, add this onSubmit handler to the form:

    <form
            className="relative w-full flex-center"
            onSubmit={(e) => {
              e.preventDefault();
              fetchPosts();
            }}
    >
            ... other things
    </form>
    

    If didn’t work, make sure the API URL you’re requesting is valid

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search