You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript/TypeScript中检查字符串是否包含子串?React搜索功能模糊匹配优化求助

Fixing React Search Bar for Fuzzy Keyword Matching

Let's get your search functionality working the way you want it—you're already halfway there, just a couple of missteps in how you're applying the filtering logic. Here's what's going wrong and how to fix it:

What's Causing the Issue

  1. You're not using your filtered results: You've already written a search function that correctly filters posts into the result state, but your rendering code is still looping through the original postList instead of using the filtered result array. That's why your includes attempts weren't having the intended effect.
  2. Reverse logic in conditional checks: Your original condition if (query !== post.title && query) return null enforces exact matches only. When you tried includes, you flipped the check (e.g., query.includes(post.title) instead of post.title.includes(query)), which checks if your search term contains the entire post title—opposite of what you need.

Step-by-Step Solution

1. Update Render Logic to Use Filtered Results

Modify your rendering section to use result when a search query exists, and fall back to postList when there's no query. This way, you're actually displaying the filtered posts you generate in the search function.

2. Remove the Broken Conditional in map

Since we're already filtering the posts before rendering, we don't need to return null for non-matching posts inside the map—just render every post in the active array (either result or postList).

Instead of requiring a button click to search, you can trigger filtering automatically as the user types by moving the search logic into a useEffect that listens for changes to query.

Modified Code

Here's your full component with the fixes applied:

import React, { useState, useEffect, useCallback } from 'react'
import api from 'services/api'
import { Link } from 'react-router-dom'
import { RectShape } from 'react-placeholder/lib/placeholders'
import { AiFillCalendar } from 'react-icons/ai'
import { FaUserCircle } from 'react-icons/fa'
import NoDataWarning from 'components/NoDataWarning'
import Can from 'components/Can'
import PayPlaceholder from 'components/PayPlaceholder'
import { Post } from 'types'
import { ButtonIcon, SearchGroup, SearchInput } from 'components/SearchBar/styles'
import { BiSearchAlt2 } from 'react-icons/bi'
import { Container, PostContainer, PostTitle, PostBanner, PostInfoContainer, PostGrid } from './styles'

const RegulatorioList: React.FC = () => {
  const [postList, setPostList] = useState<Post[]>([])
  const [isLoading, setIsLoading] = useState(true)
  const [query, setQuery] = useState('')
  const [result, setResult] = useState<Post[] | undefined>()

  const inputHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
    const enteredName = event.target.value
    setQuery(enteredName)
  }

  // This function filters posts based on the query
  const filterPosts = useCallback(() => {
    if (!query.trim()) {
      setResult(undefined) // Reset to show all posts when query is empty
      return
    }
    const foundItems = postList.filter(post => 
      post.title.toLowerCase().includes(query.toLowerCase())
    )
    setResult(foundItems)
  }, [postList, query])

  // Trigger filtering on query change (real-time search)
  useEffect(() => {
    filterPosts()
  }, [filterPosts])

  const fetchPosts = useCallback(() => {
    api
      .get<Post[]>('posts', { params: { filterInactives: true } })
      .then(response => {
        setPostList(response.data)
        setIsLoading(false)
      })
  }, [])

  useEffect(() => {
    fetchPosts()
    const interval = setInterval(fetchPosts, 180000)
    return () => clearInterval(interval)
  }, [fetchPosts])

  const LoadingBlock = () => (
    <>
      {new Array(15).fill('').map(() => (
        <RectShape color='lightgray' style={{ width: '100%', height: '350px', borderRadius: '5px' }} className='text-block' />
      ))}
    </>
  )

  // Determine which posts to render
  const postsToRender = query.trim() ? result : postList

  return (
    <Container>
      <SearchGroup position={1}>
        <SearchInput value={query} onChange={inputHandler} placeholder='Search ' />
        {/* Optional: Keep the button if you want both click and real-time search */}
        <ButtonIcon type='button' onClick={filterPosts}>
          <BiSearchAlt2 />
        </ButtonIcon>
      </SearchGroup>
      <PostGrid>
        {(() => {
          if (isLoading) return <LoadingBlock />
          if (!isLoading && (!postsToRender || postsToRender.length === 0)) {
            return <NoDataWarning text='Nenhuma postagem encontrada.' />
          }
          return postsToRender.map((post, index) => (
            <Link key={post.id} to={`/regulatorio/${post.id}`} style={{ textDecoration: 'none', height: '100%' }}>
              <PostContainer position={index}>
                <PostBanner />
                <PostInfoContainer>
                  <span>
                    <AiFillCalendar /> {new Date(post.createdAt).toLocaleDateString()}
                  </span>
                  <span>
                    <FaUserCircle /> {`${post.firstName} ${post.lastName}`}
                  </span>
                </PostInfoContainer>
                <PostTitle>{post.title}</PostTitle>
              </PostContainer>
            </Link>
          ))
        })()}
      </PostGrid>
    </Container>
  )
}

export default RegulatorioList

Key Changes Explained

  • filterPosts function: Refactored the search logic into a reusable function that checks if the post title includes the query (case-insensitive for better user experience).
  • Real-time search: Added a useEffect that calls filterPosts whenever query changes, so results update as the user types.
  • postsToRender variable: Decides whether to show filtered results or all posts based on the presence of a query.
  • Removed broken conditionals: The map now just renders every post in the active array, no more returning null for non-matching posts.
  • Fixed empty state check: Now checks postsToRender instead of postList to show the "no data" message when search returns no results.

内容的提问来源于stack exchange,提问作者Lucas Abrantes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 03:12:42