'How to get single value in react-select dropdown
I am trying to create a multi-select dropdown indicator (the second element shown here) using react-select.
The purpose is to show all blog post categories on a blog page, and then to only render the blog posts that are selected in the dropdown indicator.
The tags are extracted from their posts based on a GraphQL query and stored in useState variables "tags" and "renderedPosts".
How do I simply get a value from the dropdown when a category is added or removed? Reading the react-select API, I get this:
getValue () => ReadonlyArray<...>
I don't know how to use that, VS Code simply screams when I try add an arrow function as an attribute in the Select.
I understand there is supposed to be a "value" by default on the Select but if I try to use it I get undefined.
I don't know if mapping to the default value is a problem or if it has anything to do with the ContextProvider (which was necessary). There are other attributes I cannot get to work either, like maxMenuHeight (which is supposed to take a number).
Allow me to share my code (you can probably ignore the 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 => {
EDIT: The closest I have now come to a solution is the following:
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)}
I click to delete one option from the dropdown and I get the other two options in "tagOptions". But then if I try to change "renderedTags", the update of the state is blocked. I find this inexplicable as "setRenderedTags" has nothing to do with the rendering of the dropdown or its data!
Solution 1:[1]
with isMulti option true, you get array of options(here it's tags) from onChange callback. so I guess you could just set new tags and render filtered posts depending on the selected tags like below?
const renderedPosts = posts.filter(post => post.tags.some(tag => tags.includes(tag)))
...
onChange={selectedTags => {
setTags(selectedTags ? selectedTags.map(option => option.value) : [])
}}
...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
