如何在 react-select 下拉列表中获取单个值

How to get single value in react-select dropdown

我正在尝试使用 react-select.

创建一个多 select 下拉指示器 (the second element shown here)

目的是在博客页面上显示所有博客 post 类别,然后仅呈现在下拉指示器中 selected 的博客 post。

标签是根据 GraphQL 查询从它们的 post 中提取的,并存储在 useState 变量“tags”和“renderedPosts”中。

添加或删除类别时,我如何简单地从下拉列表中获取值? 阅读 react-select API,我明白了这个:

getValue () => ReadonlyArray<...>

我不知道如何使用它,当我尝试在 Select.

中添加箭头函数作为属性时,VS Code 只是尖叫

我知道 Select 默认情况下应该有一个“值”,但如果我尝试使用它,我会得到未定义的值。

我不知道映射到默认值是否有问题,或者它是否与 ContextProvider 有任何关系(这是必要的)。还有其他属性我也无法使用,比如 maxMenuHeight(应该是一个数字)。

请允许我分享我的代码(您可以忽略 useEffect):

export default function Blog({ data }) {
    const { posts } = data.blog

    const [tags, setTags] = useState([])
    const [renderedPosts, setRenderedPosts] = useState([])

    // Context necessary to render default options in react-select
    const TagsContext = createContext();

    // setting all tags (for dropdown-indicator) and rendered posts below the dropdown (initially these two will be the same)
    useEffect(() => {
        const arr = [];
        data.blog.posts.map(post => {
            post.frontmatter.tags.map(tag => {
                if (!arr.some(index => index.value === tag)) {
                    arr.push({ value: tag, label: tag })
                }
            })
        });
        setTags([arr]);
        setRenderedPosts([arr]);
    }, []);

    function changeRenderedPosts(value???){
        setRenderedPosts(value???)
    }

    return (
        <Layout>
            <div>
                <h1>My blog posts</h1>
                <TagsContext.Provider value={{ tags }}>
                    <Select
                        defaultValue={tags.map(tag => tag) }
                        isMulti
                        name="tags"
                        options={tags}
                        className="basic-multi-select"
                        classNamePrefix="select"
                        // HOW DO I PASS THE VALUE OF THE ADDED/DELETED OPTION?
                        onChange={() => changeRenderedPosts(value???)}
                        maxMenuHeight= {1}
                    />
                </TagsContext.Provider>
                // posts to be rendered based on renderedPosts value
                {posts.map(post => {

编辑:我现在最接近的解决方案如下:

   function changeRenderedTags(options){
        console.log(options) //logs the remaining options
        setRenderedTags(options) //blocks the change of the dropdown elements
    }

    return (
        <Layout>
            <div>
                <h1>My blog posts</h1>
                <TagsContext.Provider value={{ tags }}>
                    <Select
                      ...
                        onChange={(tagOptions) => changeRenderedTags(tagOptions)}
             

我单击以从下拉列表中删除一个选项,然后在“tagOptions”中获得其他两个选项。但是如果我尝试更改“renderedTags”,状态更新将被阻止。我觉得这莫名其妙,因为“setRenderedTags”与下拉列表或其数据的呈现无关!

如果 isMulti 选项为真,您会从 onChange 回调中获得选项数组(这里是 tags)。所以我想您可以设置新标签并根据所选标签呈现过滤后的帖子,如下所示?


const renderedPosts = posts.filter(post => post.tags.some(tag => tags.includes(tag)))

...
onChange={selectedTags => {
  setTags(selectedTags ? selectedTags.map(option => option.value) : [])
}}
...

我终于解决了 - 我不知道这是否是最好的解决方案,但它确实有效!在这里分享它以防其他人处于完全相同的情况,或者如果您只是好奇。欢迎建设性的批评。

export default function Blog({ data }) {
    const { posts } = data.blog

    const [tags, setTags] = useState([])
    const [renderedTags, setRenderedTags] = useState([])

    const TagsContext = createContext();

    useEffect(() => {
        const arr = [];
        posts.map(post => {
            post.frontmatter.tags.map(tag => {
                if (!arr.some(index => index.value === tag)) {
                    arr.push({ value: tag, label: tag })
                }
            })
        });
        setTags([...arr]);
    }, [posts]);
    
    useEffect(() => {
        setRenderedTags([...tags]);
    }, [tags])

    return (
        <Layout>
            <div>
                <h1>My blog posts</h1>
                <TagsContext.Provider value={{ tags }}>
                    <Select
                        defaultValue={tags}
                        isMulti
                        name="tags"
                        options={tags}
                        className="basic-multi-select"
                        classNamePrefix="select"
                        onChange={(tagOptions) => setRenderedTags(tagOptions ? tagOptions.map(option => option) : [])}
                        value={renderedTags}
                    />
                </TagsContext.Provider>
                {posts.map(post => 
                    (post.frontmatter.tags.some(i => renderedTags.find(j => j.value === i))) ? 
                    
                        <article key={post.id}>
                            <Link to={post.fields.slug}>
                                <h2>{post.frontmatter.title}</h2>
                                <p>{post.frontmatter.introduction}</p>
                            </Link>
                            <small>
                                {post.frontmatter.author}, {post.frontmatter.date}
                            </small>
                            <div dangerouslySetInnerHTML={{ __html: post.html }} />
                        </article>
                    
                    : null 
                )}
            </div>
        </Layout>
    )
}