I'm new in ReactJS and I'm still trying to understand the lifecycle of the components. I've been trying to set the default value of a multi react-select for sometime, but somehow it simply doesn't work. Since I'm following the 'react-select' documentation exactly the way it says, I think that my problem is relationed to React's components lifecycle.
What I'm trying to do: The objective is to make a 'edit user' screen. The multi select is where will be setted the technologies that the User works with. One User can have lots of techs.
(I'm posting here only the code that is related to the problem, making my problem easier to understand)
Getting all 'Techs' from the database:
const [allTechs, setAllTechs] = useState([]);
useEffect(() => {
async function getAllTechs(){
const response = await api.get('/api/techs');
return response.data.docs;
}
getAllTechs().then(result => {
const list = [];
result.forEach(r => {
let tech = {value: r._id, label: r.name};
list.push(tech);
})
setAllTechs(list);
});
}, []);
Getting User's techs from the database:
const [techs, setTechs] = useState([]);
let { id } = useParams();
useEffect(() => {
async function getData() {
const response = await api.get(`api/users/${id}`);
return response.data;
}
getData().then(result => {
setTechs(result.techs);
});
}, []);
After that, I'm creating a State called 'userTechsForSelect', that should be an array of objects. Those objects must have only 2 atributes: 'value' and 'label', just like the State called 'allTechs', 'cause those are the atributes that 'react-select' is asking on it's documentation. (https://react-select.com/home)
Populating 'userTechsForSelect':
const [userTechsForSelect, setUserTechsForSelect] = useState([]);
useEffect(() => {
async function getInitialTechValues(){
const list = [];
techs.map(t => {
let tech = {value: t._id, label: t.name};
list.push(tech);
})
setUserTechsForSelect(list);
}
getInitialTechValues();
}, [techs]);
Now, when I intantiate the 'Select' on my component, I use the States mentioned previously ('allTechs' as 'options' and 'userTechsForSelect' as 'defaultValue') to set its atributes:
return(
<Select
className="editUserReactSelect"
options={allTechs}
defaultValue={userTechsForSelect[0]}
closeMenuOnSelect={false}
placeholder="Select"
isMulti
styles={colourStyles}
/>
)
The options are being setted, but the default value is not. My guess is: the 'Select' component is being rendered before 'userTechsForSelect' receives its values. But if a put a 'console.log(userTechsForSelect)' before the 'Select' tag, I can see that the component is being rendered many times, and while the state is empty on first renders, it is not on the last ones.
The component exactly the way it's being rendered: [Img]Select
Console.log result: [Img]Console.log
Can anyone help me and tell why are the default values not being setted? If you want me to post any other code, just ask! Thank you!
Edit 1:
Even when I put the defaultValue
of the Select as an array, it keeps not displaying the techs that the User has.
<label className="editUserLabel">Tecnologias
{console.log(userTechsForSelect[0])}
<Select
className="editUserReactSelect"
options={allTechs}
defaultValue={[userTechsForSelect[0]]}
closeMenuOnSelect={false}
placeholder="Selecione"
isMulti
styles={colourStyles}
/>
</label>
But, when I change the defaultValue
to a fixed object (like I'm showing bellow), it works (even if I don't put it as an array, like defaultValue={exampleValue[0]}
)
const exampleValue = [{value: '5e6067ddef8a973de092403d', label: 'NodeJS'}];
return(
<label className="editUserLabel">Tecnologias
{console.log(userTechsForSelect[0])}
<Select
className="editUserReactSelect"
options={allTechs}
defaultValue={exampleValue[0]}
closeMenuOnSelect={false}
placeholder="Selecione"
isMulti
styles={colourStyles}
/>
</label>
)
The result is: here
Edit 2:
As asked, I'm going to console.log
the options
State and the defaultValue
State before the Select, so you can see that the defaultValue
should be matching with one of the options.
The code:
<label className="editUserLabel">Tecnologias
{console.log("allTechs: ")}
{console.log(allTechs)}
{console.log("userTechsForSelect: ")}
{console.log(userTechsForSelect)}
<Select
className="editUserReactSelect"
options={allTechs}
defaultValue={[userTechsForSelect[0]]}
closeMenuOnSelect={false}
placeholder="Selecione"
isMulti
styles={colourStyles}
/>
</label>
(The console.log
's are going to appear many times, 'cause the component renders many times as well, so I put another console.log
before each one to make it easier to see)
The result: [Img]console.log results
As you can see, the userTechsForSelect
array is empty in the beginning, but then it is not. I think that the Select
component is being rendered before userTechsForSelect
gets its values
userTechsForSelect
andallTechs
look like please? – larzvalue
of the objects inuserTechsForSelect[0]
matches anyvalue
inallTechs
. – larz