【问题标题】:React filtering with checkboxes使用复选框进行反应过滤
【发布时间】:2021-07-06 23:56:27
【问题描述】:

我很难用复选框输入制作过滤数组。我的问题是我只能通过其中一个过滤条件进行过滤。

例如,如果我选中了 3 个复选框,例如早餐、游泳池和健身房,我只想要我的所有数组对象中想要过滤的那些真正的复选框。但取而代之的是,它仍在过滤数组中最真实的数组。包括不真实的。当我检查所有功能时,如果我的所有条件都不成立,我希望它说“不匹配”。

我知道我的代码有点乱,但如果你能帮助我,我将不胜感激。

谢谢。

上下文 API:

const [myHotel] = useState(
            [
            {
                id: uuidv4(),
                title: "Beach Hotel",
                avaibleRoom: 16,
                hotel_img: "https://images.unsplash.com/photo-1566073771259-6a8506099945?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
                hotel_room_img: [
                        "https://images.unsplash.com/photo-1570214476695-19bd467e6f7a?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1350&q=80",
                        "https://images.unsplash.com/photo-1559599189-fe84dea4eb79?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80",
                        "https://images.unsplash.com/photo-1582582484783-0a7a9e45b0d6?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80",
                       ],    
                luks: false,
                maxCapacity: 39,
                breakfast: true,
                freeotopark: true,
                pool: true,
                wifi: true,
                gym: false,
                bar: true,
                beach: true,
                minigolf: false,
                price: 1730,
            },
    
            {
                id: uuidv4(),
                title: "Luxurios Hotel",
                avaibleRoom: 17,
                hotel_img: "https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80",
                hotel_room_img: [
                    "https://images.unsplash.com/photo-1559599238-308793637427?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80",
                    "https://images.unsplash.com/photo-1565330502637-963b256876c6?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1349&q=80",
                    "https://images.unsplash.com/photo-1559599242-651c4e085efb?ixlib=rb-1.2.1&ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&auto=format&fit=crop&w=1350&q=80",
                ],  
                luks: true,
                maxCapacity: 51,
                breakfast: true,
                freeotopark: false,
                pool: true,
                wifi: true,
                gym: true,
                bar: false,
                beach: true,
                minigolf: false,
                price: 2670,
            },

这是我的功能:

function Hotels() {
     /** CONTEXT API DATA **/
     const hotelContext = useContext(HotelsContext); 
    const {myHotel} = hotelContext; 
    
    /** NEW FILTERED HOTEL STATE  **/
    const [newHotel, setNewHotel] = useState([]);

   /** checkboxes true or false data**/
    const [handleCheck, setHandleCheck] = useState({});
    

     const handleChange =  (e) => {
            setHandleCheck({...handleCheck, [e.target.name]: e.target.checked})
        }

       useEffect(() => {
        function filterbyName (value) {
            if(handleCheck !== undefined) {
                if(handleCheck.breakfast === true) {
                    return value.breakfast === true
                } else if (handleCheck.luks === true) {
                    return value.luks === true
                } else if (handleCheck.freeotopark === true) {
                    return value.freeotopark === true
                } else if (handleCheck.pool === true) {
                    return value.pool === true
                } else if (handleCheck.wifi === true) {
                    return value.wifi === true
                } else if (handleCheck.gym === true) {
                    return value.gym === true
                } else if (handleCheck.bar === true) {
                    return value.bar === true
                } else if (handleCheck.beach === true) {
                    return value.beach === true
                } else if (handleCheck.minigolf === true) {
                    return value.minigolf === true
                } else {
                    return value
                }
            } else {
                return value
            }
        }
      
        setNewHotel(
            myHotel.filter(filterbyName)
        )
       }, [handleCheck, myHotel])

【问题讨论】:

    标签: arrays reactjs checkbox conditional-statements filtering


    【解决方案1】:

    问题是你的filterbyName 函数是错误的。一旦达到定义的过滤器选项,它会立即根据当前值是否通过该过滤器返回答案,而不检查任何其他过滤器。根据您的问题,我了解到您希望将所有过滤器应用于您的值,在这种情况下,函数应如下所示:

    function filterbyName (value) {
        if (handleCheck !== undefined) {
            let valuePassesFilters = true; // NOTE 1
    
            if (handleCheck.breakfast === true) {
                valuePassesFilters = valuePassesFilters && value.breakfast === true; // NOTE 2
            }
            
            if (handleCheck.luks === true) {
                valuePassesFilters &&= value.luks === true; // NOTE 3
            }
            
            // ...same thing for all other filters
            
            return valuePassesFilters;
        } else {
            return value;
        }
    }
    

    NOTE 1:实例化一个临时变量,该变量保存一个值是否会通过所有过滤器的问题的答案。目前确实如此,因为您还没有对其进行任何检查,所以最初它是true

    NOTE 2:如果检查了过滤器,则对value 进行测试。如果结果为true,则valuePassesFilters 将保持为true。一旦它变成false,那么通过任何其他过滤器将无济于事,它将保持false 应有的状态。

    NOTE 3:这只是NOTE 2 操作的简写符号。

    另外,请注意if 语句之间缺少else,因为您需要遍历所有语句。

    稍后编辑:这是一个等效的解决方案,我认为它更优雅,并且在将字段添加到模型(以及它们的过滤器)时,可以避免编写如此多的 if 语句:

    function filterbyName (value) {
        if (handleCheck !== undefined) {
            let filterKeys = ['breakfast', 'luks', 'freeotopark', 'pool', 'wifi', 'gym', 'bar', 'beach', 'minigolf'];
    
            return filterKeys.every(function(key) {
                return !handleCheck[key] || value[key];
            });
        } else {
            return value;
        }
    }
    

    这里我们简单地在一个数组中声明我们想要检查我们的值的过滤器:filterKeys。只要回调返回 true,every 函数就会遍历过滤器,并在遇到的第一个 false 处停止。回调中的条件非常好:如果当前过滤器未应用!handleCheck[key],将跳过第二个条件的评估),我们希望返回true 并继续执行,或者如果没有(这意味着过滤器已应用),那么如果value 通过测试(value[key]),则继续。最后value 要么通过所有过滤器,我们在检查完所有过滤器后返回true,否则我们立即在第一个不匹配的过滤器上返回false

    【讨论】:

    • 非常感谢您的详细解释和解决方案。它工作得很好。我已经努力解决了好几个小时
    • @KadirÜretir 很高兴我能帮上忙 :)
    【解决方案2】:

    如果我理解正确,您只需要匹配所有个复选框而不是任何个复选框的酒店。如果是这种情况,我建议列举选定的设施名称并测试相关酒店是否适用于所有这些属性。

    下面的大多数示例 sn-p 只是设置、创建复选框等。

    您可能最感兴趣的是filterHotels 函数,尤其是它的最后一行:

        function filterHotels () {
          // convenience function for extracting the name from an object
          const getName = ({name}) => name;
          
          // get the list of checked boxes and extract their names
          const checked = [...inputsList.querySelectorAll(':checked')].map(getName);
          
          // return the hotels that include every checked amenity
          return hotels.filter(h => checked.every(amenity => h[amenity])).map(getName);
        }
    

    假设您知道所选设施的名称,查找包含所有设施的酒店很简单:过滤酒店以仅包含 every 选中设施名称存在/真实的酒店。

    // just a convenience for creating the checkboxes
    const amenities = ['pool','gym','wifi','breakfast','bar','beach'];
    
    // sample data with varying amenities
    const hotels = [
      {
        name: 'Hotel with pool, gym, wifi',
        pool: true,
        gym: true,
        wifi: true,
      },
      {
        name: 'Hotel with gym and pool',
        pool: true,
        gym: true,
      },
      {
        name: 'Hotel with breakfast and wifi',
        breakfast: true,
        wifi: true,    
      },  
    ];
    
    // utility function for adding a checkbox with the given name
    const addCheckbox = name => {
      const item = document.createElement('li');
      item.innerHTML = `<label><input type="checkbox" name="${name}" /> ${name}</label>`;
      inputsList.appendChild(item);
    }
    
    // get a reference to the dom element containing the checkboxes
    const inputsList = document.getElementById('inputs');
    
    // creates the checkboxes, attaches the onchange handler
    function setup () {  
      // create a checkbox for each amenity
      amenities.forEach(a => addCheckbox(a));
    
      // checkbox onChange handler;
      // get the filtered hotel list and emit it to the console
      const output = () => console.log(filterHotels());
      
      // attach the onchange listener to each checkbox
      document.querySelectorAll('input[type=checkbox]')
        .forEach(input => input.addEventListener('change', output));
        
      // emit the initial list, before any clicks
      output();
    }
    
    // filter the list of hotels according to checked amenities
    function filterHotels () {
      // convenience function for extracting the name from an object
      const getName = ({name}) => name;
      
      // get the list of checked boxes and extract their names
      const checked = [...inputsList.querySelectorAll(':checked')].map(getName);
      
      // return the hotels that include every checked amenity
      return hotels.filter(h => checked.every(amenity => h[amenity])).map(getName);
    }
    
    // kick it off
    setup();
    &lt;ul id="inputs"&gt;&lt;/ul&gt;

    【讨论】:

    • 感谢您的回答。上面的另一个解决方案对我有用,但我希望有人能从你的解决方案中受益。
    猜你喜欢
    • 2017-10-11
    • 2021-11-07
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    • 2016-10-01
    • 2014-09-17
    • 2016-10-26
    • 2021-02-22
    相关资源
    最近更新 更多