I'm working on a form using react-hook-form that contains a react-select CreatableSelect multiselect input. The multiselect is used for tags of a given post and it is conditional based on if the user selects to update the tags of an existing post.
My issue is that the defaultValue for the multiselect is not working when a user selects an existing post that contains tags.
The overall flow is: User selects existing post (in PublicShareNetworkSelect in my example) > onChange function changes the post ID stored in hook (selectedNetwork in my example) > change in selectedNetwork fires getNetworkData function that sets the tags variable (networkTags) used as the multiselect defaultValue
Also the getTags() function is used to populate the options in the multiselect.
I believe that the issue as something to do with getting the data from the APIs because I tried to create a minimum reproducible example, but it works exactly how I want it to without the axios calls. However, when I console.log the allTags and networkTags in my full example, there are matching objects in the arrays (the matches should be the defaultValue).
Code example: Main/Parent form component
import React, { useState, useEffect } from "react";
import axios from "axios";
import Form from "react-bootstrap/Form";
import { useForm, Controller } from "react-hook-form";
import CreatableSelect from "react-select/creatable";
import Button from "react-bootstrap/Button";
import PublicShareNetworkSelect from "./publicShareNetworkSelect";
function PublicShareForm(props) {
const {
register,
handleSubmit,
reset,
control,
errors,
watch,
onChange,
} = useForm();
const [loading, setLoading] = useState(false);
const [selectedNetwork, setSelectedNetwork] = useState([]);
const [allTags, setAllTags] = useState();
const [networkTags, setNetworkTags] = useState([]);
//Create axios instance
const axiosSharedNetwork = axios.create();
async function getTags() {
const getAllTagsApi = {
url: "/public-share/get-all-tags",
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
method: "GET",
};
await axiosSharedNetwork(getAllTagsApi)
.then((response) => {
const resData = response.data;
const tags = resData.map((tag, index) => ({
key: index,
value: tag.tag_id,
label: tag.name,
}));
setAllTags(tags);
setLoading(false);
})
.catch((error) => {
console.log(error.response);
});
}
async function getNetworkData(networkId) {
const getNetworkDataApi = {
url: "/public-share/get-network/" + networkId,
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
method: "GET",
};
const getNetworkTagsApi = {
url: "/public-share/get-network-tags/" + networkId,
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
method: "GET",
};
await axiosSharedNetwork(getNetworkDataApi)
.then(async (response) => {
const resData = response.data;
//Set some variables (i.e. title, description)
await axiosSharedNetwork(getNetworkTagsApi)
.then(async (response) => {
const tagResData = response.data;
const tags = tagResData.map((tag, index) => ({
key: index,
value: tag.tag_id,
label: tag.name,
}));
setNetworkTags(tags);
setLoading(false);
})
.catch((error) => {
console.log(error.response);
});
})
.catch((error) => {
console.log(error.response);
});
}
useEffect(() => {
getTags();
getNetworkData(selectedNetwork);
reset({ tags: selectedNetwork });
}, [reset]);
async function onSubmit(data) {
//Handle submit stuff
}
console.log(allTags);
console.log(networkTags);
return (
<Form id="public-share-form" onSubmit={handleSubmit(onSubmit)}>
<Form.Group>
<Form.Label>Create New Version of Existing Shared Network?</Form.Label>
<PublicShareNetworkSelect
control={control}
onChange={onChange}
setSelectedNetwork={setSelectedNetwork}
/>
<Form.Label>Tags</Form.Label>
<Controller
name="tags"
defaultValue={networkTags}
control={control}
render={({ onChange }) => (
<CreatableSelect
isMulti
placeholder={"Select existing or create new..."}
onChange={(e) => onChange(e)}
options={allTags}
defaultValue={networkTags}
classNamePrefix="select"
/>
)}
/>
</Form.Group>
<Button variant="secondary" onClick={props.handleClose}>
Cancel
</Button>
<Button variant="primary" type="submit">
Share
</Button>
</Form>
);
}
export default PublicShareForm;
PublicShareNetworkSelect - the select component that triggers the function to set the existing post id (selectedNetwork):
import React, { useState, useEffect } from "react";
import axios from "axios";
import { Controller } from "react-hook-form";
import Select from "react-select";
function PublicShareNetworkSelect(props) {
const [loading, setLoading] = useState(false);
const [networks, setNetworks] = useState([]);
//Create axios instance
const axiosNetworks = axios.create();
// Add a request interceptor
axiosNetworks.interceptors.request.use(
function (config) {
// Do something before request is sent
setLoading(true);
return config;
},
function (error) {
// Do something with request error
setLoading(false);
return Promise.reject(error);
}
);
// Add a response interceptor
axiosNetworks.interceptors.response.use(
function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
setLoading(true);
return response;
},
function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
setLoading(false);
return Promise.reject(error);
}
);
async function getNetworks() {
const getNetworksApi = {
url: "public-share/get-user-networks/" + props.username,
method: "GET",
};
await axiosNetworks(getNetworksApi)
.then(async (response) => {
setNetworks(
response.data.map((network, index) => ({
key: index,
value: network.network_id,
label: network.title,
}))
);
setLoading(false);
})
.catch((error) => {
console.log(error.response);
});
}
useEffect(() => {
getNetworks();
}, []);
function handleChange(data) {
console.log(data);
if (data) {
props.setSelectedNetwork(data.value);
props.getNetworkData(data.value);
} else {
props.setNetworkTitle("");
props.setNetworkDesc("");
}
}
if (!loading) {
if (networks.length === 0) {
return (
<React.Fragment>
<br />
<p className="font-italic text-muted">
You haven't created any public networks yet.
</p>
</React.Fragment>
);
} else {
return (
<Controller
name="tags"
defaultValue={[]}
control={control}
render={(props) => (
<CreatableSelect
isMulti
placeholder={"Select existing or create new..."}
onChange={(e) => onChange(e)}
// defaultValue={networkTags}
options={allTags}
classNamePrefix="select"
{...props}
/>
)}
/>
);
}
} else {
return <React.Fragment>Loading...</React.Fragment>;
}
}
export default PublicShareNetworkSelect;
Edit 1: console.log output for allTags (options) and networkTags (defaultValue)
