I have a tabbed modal dialog and in one of my tabs I am rendering two image list components. Each component manages an array of image objects based on some props that are defined in the parent. In my dialog I have a single save button and I need to call the backend api to update or delete any image state from either of the image list components. For example
function MyItem() {
function handleSave() {
// How would I get the state from my ImageList components?
}
//other handlers
return (
<TabPanel index={0} title="Detail">
<HeaderWithSaveButton onSaveClick={handleSave} />
<SomeTextContent/>
</TabPanel>
<TabPanel index={1} title="Images">
<ImageList key="banner" />
<ImageList key="icon" />
</TabPanel>
)
}
The ImageList components maintain their own state in an array about the images that are added or removed.
function ImageList({key}) {
const [images, setImages] = useState([{imageKey: key, url:`/images/${key}`, fileData: null}])
function handleImageSelected(image){
setImages() // add image
}
// other handlers
return (
<ImageUploader/>
<SortedImageList images={images} />
)
}
I have the image list working but obviously the state is local to each one, so I have no way to access it in the parent's save button in Item component.
Is this something I can use Context for? Would there have to be two contexts that will be merged? If I lifted the state up to the Item component, how would I keep track of both of those arrays? Also, the item component is getting bloated already.
But the basic question is an approach to manage the state in the two image lists yet access it in the parent so I can figure out what needs to be sent to the api when they save.
You could pass a state update function to each component to allow them to update the state of their parent. I'm not sure if this is a particularly 'React-y' way to do it but something like:
function MyItem() {
const [imageState, setImageState] = useState({});
function handleSave() {
// Use imageState to access the images
}
//other handlers
return (
<TabPanel index={0} title="Detail">
<HeaderWithSaveButton onSaveClick={handleSave} />
<SomeTextContent/>
</TabPanel>
<TabPanel index={1} title="Images">
<ImageList key="banner" setImageState={setImageState} />
<ImageList key="icon" setImageState={setImageState} />
</TabPanel>
)
}
And then your ImageList component can use the passed state setter to inform the parent component:
function ImageList({key, setImageState}) {
const [images, setImages] = useState([{imageKey: key, url:`/images/${key}`, fileData: null}])
function handleImageSelected(image){
setImages() // add image
setImageState((current) => {
return {
...current,
[key]: image,
}
})
}
// other handlers
return (
<ImageUploader/>
<SortedImageList images={images} />
)
}
The other solution is to 'raise' the state to the parent component