【问题标题】:How can I filter results by category id in ReactJS如何在 ReactJS 中按类别 id 过滤结果
【发布时间】:2021-10-24 06:03:33
【问题描述】:

我正在尝试通过过滤来呈现书签卡。我有一个调用 filterByCategory 的事件处理程序。在那里,我调用我的道具来遍历书签集合并仅返回其 category_id 与 e.target 的值匹配的 BookmarkCard;其中“e.target”是下拉菜单的选定选项。

这是我的代码:

//containers/Bookmarks.js
import React from 'react'
import BookmarkCard from './BookmarkCard'
import BookmarkForm from '../components/BookmarkForm'
import CategoryForm from '../components/CategoryForm'
import Select from '@material-ui/core/Select'
import MenuItem from '@material-ui/core/MenuItem' 
import { connect } from 'react-redux'
import { filterByCategory } from '../actions'


const Bookmarks = (props) => {
  
    
    const renderBookmarkCollection = () => {
        return props.bookmarks.map(bookmark => {
            return <BookmarkCard key={bookmark.id} {...bookmark}/>
        })

    }

    const filterByCategory = (e) => {
        debugger
        props.bookmarks.map((bookmark) => {
            if (bookmark.category_id == e.target.value) {
                return <BookmarkCard key={bookmark.id} category_id={bookmark.category_id} {...bookmark}/> 
            } else {
                return null 
            }
        })
    }
    

    return (
        <div className="bookmarks-container">
            <br></br>
            <BookmarkForm />
            <CategoryForm/>
            <form className="filter-category">
                    <p>FILTER BY CATEGORY</p>
                    <Select id="category-input" value={props.categories} onChange={(e) => filterByCategory(e)}>
                        {props.categories.map(category => {
                            return (
                                <MenuItem key={category.id} name={category.name} value={category.id} >{category.name}</MenuItem>
                            )
                        })}
                    </Select>
                </form>
            <br></br>
            {renderBookmarkCollection()}      
        </div>
    )

}

const mapStateToProps = (currentState) => {
    return {
      bookmarks: currentState.bookmarks.bookmarks,
      categories: currentState.categories.categories
    }
}

const mapDispatchToProps = (dispatch) => {
    return {
        filterByCategory: (id) => dispatch(filterByCategory(id))
    }
}



export default connect(mapStateToProps, mapDispatchToProps)(Bookmarks)

有了这个,我不会返回任何“书签卡”。

//containers/BookmarkCard.js
import React from 'react'
import Button from "@material-ui/core/Button"
import DeleteIcon from "@material-ui/icons/Delete"
import FavoriteIcon from "@material-ui/icons/Favorite"
import { useHistory } from 'react-router-dom'
import { connect } from 'react-redux'
import { deleteBookmark, favoriteBookmark } from '../actions/index'


const BookmarkCard = (props) => {
    const history = useHistory()


    const handleFavorite = () => {
        favoriteBookmark()
        history.push('/bookmarks')
    }

    const handleDelete = () => {
       deleteBookmark()
       history.push('/bookmarks')
    
    }

   

    return (
        <div className="bookmark-card" id={`bookmark-${props.id}`}>
            <h2 className="bookmark-headline">{props.headline}</h2>
                <p className="bookmark-description">{props.description}</p>
                <p className="bookmark-web-url" >{props.web_url}</p>
                <Button 
                    id={props.id}
                    onClick={handleFavorite}
                    className="favorite-button" 
                    startIcon={<FavoriteIcon/>}>
                </Button><br></br>
                <Button
                    id={props.id}
                    size="small"
                    startIcon={<DeleteIcon />}
                    onClick={handleDelete}
                    className="delete-button">
                </Button><br></br>
        </div>

    )
}


    
const mapDispatchToProps = (dispatch) => {
    return {
      deleteBookmark: (id) => dispatch(deleteBookmark(id)),
      favoriteBookmark: (id) => dispatch(favoriteBookmark(id))
    }
}
  
export default connect(null, mapDispatchToProps)(BookmarkCard)

【问题讨论】:

  • 在第一次渲染时您已经看不到类别了吗?或者只有过滤器不工作
  • @iunfixit 在第一次渲染时我看到了所有的书签卡;我没有看到过滤后的结果。

标签: javascript reactjs components react-component


【解决方案1】:

这里的问题是你试图从回调中返回 JSX,而这根本不是 React 的工作方式。所有你想要渲染的东西都需要从组件的函数体中返回。

添加本地状态来保存类别id过滤器值并在渲染时过滤props数组。

const Bookmarks = (props) => {
  const [categoryId, setCategoryId] = React.useState("");
    
  const renderBookmarkCollection = () => {
    return props.bookmarks
      .filter(bookmark => bookmark.category_id === categoryId))
      .map(bookmark => {
        return <BookmarkCard key={bookmark.id} {...bookmark}/>
      });
  }

  const filterByCategory = (e) => {
    setCategoryId(e.target.value);
  }
    

  return (
    <div className="bookmarks-container">
      <br></br>
      <BookmarkForm />
      <CategoryForm/>
      <form className="filter-category">
        <p>FILTER BY CATEGORY</p>
        <Select
          id="category-input"
          value={props.categories}
          onChange={filterByCategory}
        >
          {props.categories.map(category => {
            return (
              <MenuItem
                key={category.id}
                name={category.name}
                value={category.id}
              >
                {category.name}
              </MenuItem>
            )
          })}
        </Select>
      </form>
      <br></br>
      {renderBookmarkCollection()}      
    </div>
  );
}

【讨论】:

  • 我必须使用钩子吗?我正在尝试从 Redux 商店全局使用状态。我应该在之前提到过。
  • @AdriDipietro 由于您没有在全球范围内存储您的搜索值,因此我认为某些本地状态保存该搜索值没有任何问题。除非您实际上 想要 将搜索值存储在您的 redux 存储中,然后在这种情况下,您将需要使用 useSelector 钩子再次选择该状态映射前内联过滤。或者您可以同时选择书签数组选择器中的搜索值并返回过滤后的数组。有几种方法可以做到这一点,但它们可能涉及存储搜索词somewhere
  • @AdriDipietro React 组件状态和 redux 存储不是相互排斥的。每个都有一个目的和用例。
  • 谢谢德鲁!我现在知道了。我希望有一个无状态组件;所以我以后可能会开发它。
  • @AdriDipietro 恐怕您将无法完全无国籍来完成此任务。在 React 中,状态和/或道具更新是触发重新渲染的原因,在这种情况下需要重新渲染才能看到新过滤的数据。
【解决方案2】:

Map 返回一个新数组,它不会更改现有数组。此外,您不应该尝试修改道具,它是不可变的。

这里我在组件挂载时将书签放在一个状态中,当您更改类别时,它将使用作为道具传递的原始书签更新状态,这是一个示例(我没有编码)

const Bookmarks = (props) => {
  const [ bookmarks, setBookmarks ] = React.useState([])

  React.useEffect(() => {
    setBookmarks(props.bookmarks)
  }, [props.bookmarks])
    
    const renderBookmarkCollection = () => {
      return bookmarks.map(bookmark => {
        return <BookmarkCard key={bookmark.id} {...bookmark}/>
      })
    }

    const filterByCategory = (e) => {
        debugger
        // This is filtering from props.bookmarks, which should be the original array
        setBookmarks(props.bookmarks.map((bookmark) => {
            if (bookmark.category_id == e.target.value) {
                return <BookmarkCard key={bookmark.id} category_id={bookmark.category_id} {...bookmark}/> 
            } else {
                return null 
            }
        }))
    }
    

    return (
        <div className="bookmarks-container">
            <br></br>
            <BookmarkForm />
            <CategoryForm/>
            <form className="filter-category">
                    <p>FILTER BY CATEGORY</p>
                    <Select id="category-input" value={props.categories} onChange={(e) => filterByCategory(e)}>
                        {props.categories.map(category => {
                            return (
                                <MenuItem key={category.id} name={category.name} value={category.id} >{category.name}</MenuItem>
                            )
                        })}
                    </Select>
                </form>
            <br></br>
            {renderBookmarkCollection()}      
        </div>
    )

}

【讨论】:

  • 虽然我相信这在技术上是可行的,但将派生状态存储在 React 状态中被认为是反模式。请参阅Thinking in React: Identify The Minimal (but complete) Representation Of UI State 特别指出 (1) “它是通过 props 从父级传递的吗?如果是,它可能不是状态。” (3) “你可以根据组件中的任何其他状态或道具来计算它吗?如果可以,它就不是状态。”
  • 我将 OP 代码更改为按照他设计的方式工作,我无意在不知道他对组件的意图的情况下重构他的代码
【解决方案3】:

我以前做过。希望我的问题能解决你的问题。

import react, { useState, useEffect }  from 'react';

// This is an array 
const [filteringBookmark, setFilteringBookmark] = useState([]);
// text for you filter
const [ search , setSearch ] = useState('');

// This code output an array maybe complete or filtered while your main 
// array ( bookmarks ) change or text of search change too.
useEffect( () => {
  setFilteringBookmark( bookmarks.filter( book => {
     // filter your text to lowercase if you want  
    return book.includes( search.toLowerCase() )
  }) 
 )
}, [search, bookmarks])

所以在你的 jsx 中它会是这样的:

 <form className="filter-category">
   <p>FILTER BY CATEGORY</p>
   <Select id="category-input" value={props.categories} onChange={(e) => 
    setSearch(e)}
   >
     {filteringBooksmark.map(category => (
      <MenuItem key={category.id} name={category.name} value={category.id} > 
            {category.name}
      </MenuItem>
     )}
   </Select>
 </form>

我希望它有效!

【讨论】:

    猜你喜欢
    • 2012-07-12
    • 2019-12-07
    • 2011-04-06
    • 2020-08-20
    • 1970-01-01
    • 2012-08-10
    • 2015-12-16
    • 2013-08-29
    • 2022-12-06
    相关资源
    最近更新 更多