admin管理员组

文章数量:1405170

I'm building a multiselect dropdown with a field to search for options. It's working perfectly except for one aspect:

1 - Here I just selected the options. The first input shows the state of the variable:

2 - Here I searched for values with the digit "4". The option "4" is already selected, but I didn't do this, I selected options "1" and "3":

Here's is the components' code (I removed the parts that doesn't matter about this issue like tailwind notations and functions that is not used by the filter logic):

"use client"
import React, { useEffect, useId, useState } from "react"

export default function Cscheckdropdown(props: Props) {

    const inputText = useId()
    const inputSearch = useId()

    const [value, setValue] = useState < string[] > ([])
    const [searchValue, setSearchValue] = useState("")
    const [optionsFiltered, setOptionsFiltered] = useState(props.options.map((option) => { return option }))

    const handleSetValue = (e: React.MouseEvent<HTMLInputElement>) => {
        const valor = e.currentTarget.value

        if (!value.includes(valor)) {
            setValue([...value, valor])
        }
        else if (value.includes(valor)) {
            setValue(value.filter(v => v != valor))
        }
    }

    useEffect(() => {
        setOptionsFiltered(
            props.options.filter((x) => {
                if (x.includes((searchValue))) {
                    return x
                }
            })
        )
    }, [props.options, searchValue])

    return (<>
        <div>
            <input id={inputSearch} name={props.name + "_inputSearch"} type="text" onChange={(e) => { setSearchValue(e.currentTarget.value) }} value={searchValue} />
        </div>
        {
            optionsFiltered.map((option, index) => {
                return (
                    <div key={index}>
                        <label htmlFor={inputText + index}>
                            <input type="checkbox" id={inputText + index} name={props.name} value={option} onClick={handleSetValue} />
                            {option}
                        </label>
                    </div>
                )
            })
        }
    </>
    )
}

I'm building a multiselect dropdown with a field to search for options. It's working perfectly except for one aspect:

1 - Here I just selected the options. The first input shows the state of the variable:

2 - Here I searched for values with the digit "4". The option "4" is already selected, but I didn't do this, I selected options "1" and "3":

Here's is the components' code (I removed the parts that doesn't matter about this issue like tailwind notations and functions that is not used by the filter logic):

"use client"
import React, { useEffect, useId, useState } from "react"

export default function Cscheckdropdown(props: Props) {

    const inputText = useId()
    const inputSearch = useId()

    const [value, setValue] = useState < string[] > ([])
    const [searchValue, setSearchValue] = useState("")
    const [optionsFiltered, setOptionsFiltered] = useState(props.options.map((option) => { return option }))

    const handleSetValue = (e: React.MouseEvent<HTMLInputElement>) => {
        const valor = e.currentTarget.value

        if (!value.includes(valor)) {
            setValue([...value, valor])
        }
        else if (value.includes(valor)) {
            setValue(value.filter(v => v != valor))
        }
    }

    useEffect(() => {
        setOptionsFiltered(
            props.options.filter((x) => {
                if (x.includes((searchValue))) {
                    return x
                }
            })
        )
    }, [props.options, searchValue])

    return (<>
        <div>
            <input id={inputSearch} name={props.name + "_inputSearch"} type="text" onChange={(e) => { setSearchValue(e.currentTarget.value) }} value={searchValue} />
        </div>
        {
            optionsFiltered.map((option, index) => {
                return (
                    <div key={index}>
                        <label htmlFor={inputText + index}>
                            <input type="checkbox" id={inputText + index} name={props.name} value={option} onClick={handleSetValue} />
                            {option}
                        </label>
                    </div>
                )
            })
        }
    </>
    )
}

Share Improve this question asked Mar 23 at 20:05 Thiago BarbozaThiago Barboza 175 bronze badges 0
Add a comment  | 

1 Answer 1

Reset to default 1

Your checkbox element has no checked attribute. I was expecting to see something like checked={value.includes(option)}. It looks like you're relying on the DOM saving the selection; it needs to be state driven.

Further, option makes a better key than than index. That's probably why you're seeing the first option remaining selected, even after filtering.

Finally, your optionsFiltered variable would be better written as a memo, rather than a state variable with an effect hook. i.e.

const optionsFiltered = useMemo(() => {
    return props.options.filter((opt) => {
        return opt.includes(searchValue);
    });
}, [props.options, searchValue]);

本文标签: reactjsMultiselect dropdown doesn39t keep the right input checkedStack Overflow