Hi i am using multiselect-react-dropdown for selecting multiple options in my admin panel.
Getting relational data from API, which is working fine. now when i load/render the edit page the selectedValues variable got empty in first 4 attempts & on 5th attempt this variable fill by value. that is the reason selectedValues not updating in edit page. let me share code.
Edit.js
import { useEffect, useState } from "react"
import { useDispatch, useSelector } from "react-redux"
import InputText from '../../../components/Input/InputText'
import { showNotification } from "../../common/headerSlice"
import { getCommonListings } from "../../../services/CommonService"
import TitleCard from "../../../components/Cards/TitleCard"
import MultiSelectBox from "../../../components/Input/MultiSelectBox"
import { showCategory, updateCategory } from "../../../services/CategoryService"
import { useNavigate, useParams } from "react-router-dom"
import InputFile from "../../../components/Input/InputFile"
import InputSlug from "../../../components/Input/InputSlug"
import { NO_IMAGE } from "../../../utils/globalConstantUtil"
import { list } from "postcss"
const INITIAL_CATEGORY_OBJ = {
id : "",
title : "",
slug : "",
websites : [],
image : ""
}
const getIDs = (arr) => {
let ids = [];
arr.forEach(ar => {
ids.push(ar.id);
});
return ids;
}
function Edit(){
const params = useParams();
const dispatch = useDispatch()
const [loading, setLoading] = useState(false)
const [selectedWebsites, setSelectedWebsites] = useState([]);
const [errorMessage, setErrorMessage] = useState([])
const [defaultImage, setDefaultImage] = useState("")
const websites = useSelector(state => state.category.websites)
const [categoryObj, setCategoryObj] = useState({})
useEffect(() => {
dispatch(getCommonListings())
dispatch(showCategory({...params}))
.unwrap()
.then(res => {
let get_category_detail = res.data;
INITIAL_CATEGORY_OBJ.id = get_category_detail.id;
INITIAL_CATEGORY_OBJ.title = get_category_detail.title;
INITIAL_CATEGORY_OBJ.slug = get_category_detail.slug;
INITIAL_CATEGORY_OBJ.websites = getIDs(get_category_detail.websites);
setCategoryObj(INITIAL_CATEGORY_OBJ);
setDefaultImage(get_category_detail.image);
setSelectedWebsites(get_category_detail.websites)
})
}, [])
const navigate = useNavigate();
const doUpdate = () => {
setLoading(true);
console.log(categoryObj);
dispatch(updateCategory({...categoryObj}))
.unwrap()
.then((res) => {
if(res.success){
dispatch(showNotification({message : res.message, status : 1}))
navigate('/app/categories');
}
else{
setErrorMessage(res.data)
dispatch(showNotification({message : res.message, status : 0}))
}
setLoading(false);
})
.catch((e) => {
dispatch(showNotification({message : e.message, status : 0}))
setLoading(false);
})
}
const updateFormValue = ({updateType, value}) => {
setCategoryObj({...categoryObj, [updateType]: value});
if(updateType === 'title')
setCategoryObj(prevState => ({...prevState, slug:value.replace(/\s+/g, '-').toLowerCase()}))
}
const updateFileValue = (file) => {
if(!file)
return
setCategoryObj({...categoryObj, image : file})
}
const setupMultiSelectList = ({updateType, listObj}) =>{
setCategoryObj({...categoryObj, websites : listObj.map(lst => lst.id)})
}
return(
<>
<TitleCard title="Edit Category" topMargin="mt-2">
<InputText type="text" labelTitle="Title" error={errorMessage['title'] ? errorMessage['title']:''} updateType="title" defaultValue={categoryObj.title} updateFormValue={updateFormValue}/>
<InputSlug error={errorMessage['slug'] ? errorMessage['slug']:''} slug={categoryObj.slug} />
<div className="mask mask-squircle w-12 h-12">
<img src={defaultImage ? process.env.REACT_APP_URL+defaultImage : NO_IMAGE} alt="Avatar" />
</div>
<InputFile type="file" error={errorMessage['image'] ? errorMessage['image']:''} updateType="image" containerStyle="mt-4" labelTitle="Image" updateFileValue={updateFileValue}/>
<MultiSelectBox
labelTitle='Websites'
updateType="websites"
selectedValues={selectedWebsites}
options={websites}
error={errorMessage['websites'] ? errorMessage['websites']:''}
setupMultiSelectList={setupMultiSelectList}
/>
<div className="mt-16"><button className="btn btn-primary float-right" onClick={() => doUpdate()}>Update</button></div>
</TitleCard>
</>
)
}
export default Edit
MultiSelectBox.js
import Multiselect from "multiselect-react-dropdown"
import { useEffect, useState } from "react"
function MultiSelectBox({labelTitle, updateType, options, error, setupMultiSelectList, selectedValues}){
console.log(selectedValues); //will show value on 5th attempt
const [listObj, updateListObj] = useState(selectedValues);
const onSelect = (selectedList, selectedItem) => {
updateListObj([...listObj, selectedItem])
}
const onRemove = (selectedList, removedItem) => {
updateListObj(listObj.filter(item => item.id !== removedItem.id));
}
useEffect(() => {
setupMultiSelectList({updateType,listObj})
},[listObj])
return(
<div className="form-control w-full">
<label className="label">
<span className="label-text text-base-content">{labelTitle}</span>
</label>
<Multiselect
options={options}
onSelect={onSelect}
onRemove={onRemove}
displayValue="name"
selectedValues={selectedValues}
/>
{error ?
<span className="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{error}
</span>:
''
}
</div>
)
}
export default MultiSelectBox
console output

you need to fix this.
try this instead
remove the local state and useEffect you don't need that here