简体   繁体   中英

How to get state from two child components in React

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM