简体   繁体   English

如何使用反应挂钩有条件地重置 state 计数

[英]How to conditionally reset state count with react hooks

After the user submits my form, the handleSubmit function runs and counts the number of li elements with class names containing "show" in my div showing all search results.用户提交我的表单后, handleSubmit function 运行并计算li元素的数量,其中 class 名称在我的div中包含“show”,显示所有搜索结果。 It adds these counts all up with setStoreCount(prevCount => prevCount + 1) and I update my FAQ {searchCount} UI showing the number of search results with它将这些计数与setStoreCount(prevCount => prevCount + 1) ,我更新了我的FAQ {searchCount} UI,显示搜索结果的数量

useEffect(() => {
  setSearchCount(storeCount) // collect all storeCount
}, [storeCount])

The problem: Say that the first search gets 5 results.问题:假设第一次搜索得到 5 个结果。

Then the UI would show FAQ 5 .然后 UI 将显示FAQ 5 If you search the same thing again, you still get 5 results and would expect the UI to still show FAQ 5 but because the storeCount cannot reset to 0 it shows FAQ 10 (5 + 5) and then FAQ 15 (5 + 5 + 5) and so on.如果您再次搜索相同的内容,您仍然会得到 5 个结果,并且希望 UI 仍会显示FAQ 5 ,但由于storeCount无法重置为0 ,它会显示FAQ 10 (5 + 5),然后显示FAQ 15 (5 + 5 + 5 ) 等等。

Because my useEffect conditionally runs whenever storeCount changes, I cannot reset it to 0 because then I would always show FAQ 0 .因为只要storeCount更改,我的 useEffect 就会有条件地运行,因此我无法将其重置为 0,因为那样我将始终显示FAQ 0

How do I show the number of search results while refreshing the count on every search in the code below?如何在下面的代码中刷新每次搜索的计数时显示搜索结果的数量?

import React, { useState, useRef, useEffect } from 'react'

import ContentsWrap from '../../components/contents-wrap'
import FrequentList from './tabs/frequent'
import EstimateList from './tabs/estimate'
import ReturnList from './tabs/return'
import EtcList from './tabs/etc'
import SubsidiaryList from './tabs/subsidiary'
import ServiceList from './tabs/service'
import InList from './tabs/in'
import OutList from './tabs/out'

import styles from './index.module.scss'

export default function FAQ () {
  const [tab, setTab] = useState('frequent')
  const [storeText, setStoreText] = useState('') // stores searchbar text as user types
  const [searchText, setSearchText] = useState('') // sends searchbar text to List component props on form submit
  const [storeCount, setStoreCount] = useState(0) // stores count of each li element className that includes 'show'
  const [searchCount, setSearchCount] = useState(0) // shows search count in UI
  const searchContainer = useRef(null)
  const handleSubmit = e => {
    e.preventDefault()
    setSearchText(storeText)
    setTab('all')
    setTimeout(() => {
      // gets all <ul> children of <div class = "faq-list-wrap">
      for (let i = 0; i < searchContainer.current.children.length; i++) {
      // gets all <li> children of each <ul>
        for (let j = 0; j < searchContainer.current.children[i].children.length; j++) {
        // checks if each li class name has 'show'
          if (searchContainer.current.children[i].children[j].className.includes('show')) {
            console.log('count added')
            setStoreCount(prevCount => prevCount + 1)
          }
        }
      }
    }, 100) // setTimeOut needed to target searchContainer after search and not before
  }
  const handleChange = newId => {
    setTab(newId)
    setStoreText('') // clear input value on tab click
    setSearchText('') // show all search items on tab click
  }
  useEffect(() => {
    setSearchCount(storeCount) // collect all storeCount
  }, [storeCount])
  return (
    <ContentsWrap>
      <div className="content-wrap content-width">
        {/* <!-- S: faq-wrap --> */}
        <div className="faq-wrap">
          <div className="faq-title-wrap"><h2 className="title">FAQ {searchCount}</h2></div>
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              placeholder="Search"
              className={styles.searchBox}
              value={storeText}
              onChange={e => {
                setStoreText(e.target.value)
              }}
            />
          </form>

          {/* <!-- S: faq-list-wrap --> */}
          <div className="faq-list-wrap" ref={searchContainer} >
            {tab === 'all' && (
              <>
                <FrequentList searchText={searchText} />
                <EstimateList searchText={searchText} />
                <ReturnList searchText={searchText} />
                <EtcList searchText={searchText} />
                <SubsidiaryList searchText={searchText} />
                <ServiceList searchText={searchText} />
                <InList searchText={searchText} />
                <OutList searchText={searchText} />
              </>
            )}
            {tab === 'frequent' && (
              <FrequentList searchText={searchText}/>
            )}
            {tab === 'estimate' && (
              <EstimateList searchText={searchText}/>
            )}
            {tab === 'return' && (
              <ReturnList searchText={searchText} />
            )}
            {tab === 'subsidiary' && (
              <SubsidiaryList searchText={searchText} />
            )}
            {tab === 'service' && (
              <ServiceList searchText={searchText} />
            )}
            {tab === 'in' && (
              <InList searchText={searchText} />
            )}
            {tab === 'out' && (
              <OutList searchText={searchText} />
            )}
            {tab === 'etc' && (
              <EtcList searchText={searchText} />
            )}
          </div>
          {/* <!-- E: faq-list-wrap --> */}
        </div>
        {/* <!-- E: faq-wrap --> */}
      </div>
    </ContentsWrap>
  )
}

The problem here is in your setStoreCount logic.这里的问题在于您的setStoreCount逻辑。

In this line in your for loop:在你的for循环的这一行中:

if (searchContainer.current.children[i].children[j].className.includes('show')) {
    console.log('count added')
    setStoreCount(prevCount => prevCount + 1)
}

It adds the 1 to the prevCount meaning if the prevCount is 5 (which is the number of results on the first search, it adds 1 to that and so on.如果prevCount为 5,它将向prevCount添加 1(这是第一次搜索的结果数,它添加 1 等等。

What you can do is reset the storeCount before you add the number of elements found.您可以做的是在添加找到的元素数量之前重置storeCount like so:像这样:

setTimeout(() => {
      setStoreCount(0)
      // gets all <ul> children of <div class = "faq-list-wrap">
      for (let i = 0; i < searchContainer.current.children.length; i++) {
      // gets all <li> children of each <ul>
        for (let j = 0; j < searchContainer.current.children[i].children.length; j++) {
        // checks if each li class name has 'show'
          if (searchContainer.current.children[i].children[j].className.includes('show')) {
            console.log('count added')
            setStoreCount(prevCount => prevCount + 1)
          }
        }
      }
    }, 100) // setTimeOut needed to target searchContainer after search and not before

But this might make it like, it show FAQ 0 then the rest of the count after it loops.但这可能会像,它显示FAQ 0 ,然后是循环后计数的rest。 So I suggest count it first before you set the count, like so.所以我建议在设置计数之前先计算它,就像这样。

setTimeout(() => {
      let count = 0
      // gets all <ul> children of <div class = "faq-list-wrap">
      for (let i = 0; i < searchContainer.current.children.length; i++) {
      // gets all <li> children of each <ul>
        for (let j = 0; j < searchContainer.current.children[i].children.length; j++) {
        // checks if each li class name has 'show'
          if (searchContainer.current.children[i].children[j].className.includes('show')) {
            console.log('count added')
            count++
          }
        }
      }
      setStoreCount(count)
    }, 100) // setTimeOut needed to target searchContainer after search and not before

Your loop is just incrementing the storeCount perpetually.您的循环只是永久增加 storeCount 。 You should start a counter at zero at the start of the loop the loop and then assign the final value of the counter into your storeCount using setStoreCount.您应该在循环开始时从零开始一个计数器,然后使用 setStoreCount 将计数器的最终值分配给您的 storeCount。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM