how to access data from child tags in react

Viewed 1298

I'm trying to make sure my custom parent components can have access to any children inside of them. I am trying to accomplish a setup similar to:

function App() {
  return (
    <div className="App">

      <Parent>
          <img src={spaceGasImg} height='100px' width='100px'></img>
      </Parent>

    </div>
  );
}

I'd like to be able to get the data from my img tag into my parent and potentially even be able to remove the img tag from the parent on a hook. I'm not sure if this is best handled by using higher order components?

Is there a way to setup my parent component such that it assumes anything wrapped inside of it is a child and can read all the data of that child?

any advice on laying out how this relationship should work is greatly appreciated :)

2 Answers

In React you can either:

1 - Pass variables as props down to let your child components know this value declared above.

2 - Pass methods as props down that set a state value on the parent component to pass a child value above

These are the two basic ways to communicate components. There is no way you can share a child value with parent without declaring a state on the parent and providing the child the method to update it.

If you do not want to pass values all the way down, but even though you want all the children to be aware of something the best approach IMHO is using the Context API and Hooks. In your example it would be like:

const ImgContext = React.createContext()

function App() {
  return (
    <div className="App">

    <ImgContext.Provider value={spaceGasImg}> // the name of this prop MUST be 'value'
      <Parent> 
        <Child />
      </Parent>
    </ImgContext.Provider>

    </div>
  );
}

function Child() {
  // Every component inside the Provider will have the value available in the 
  // useContext hook with the context as a parameter. 

  const contextValue = useContext(ImgContext) // spaceGasImg

  return (
    <img src={contextValue} />
  )

}

Every child component of <ImgContext.Provider /> that makes use of useContext has access to the value prop passed on the provider

I will recommend you to take a look at React.context (https://reactjs.org/docs/context.html), you will learn a lot.

Here is how I think you will need to process: Create a custom Parent component, with a context attached to it, then create function that will be able to generate your list of img tags, and function to alter them (removeImage(), updateImage(), getImage(), ..).

  1. Create your own Context:
const MyContext = React.createContext(defaultValue);
  1. Create your Parent state:
this.state = {
  images: [
      {
        id: 1
        url:'url1',
        height: '400px',
        width: '400px'
      }, 
      {
        id: 2
        url:'url2',
        height: '400px',
        width: '400px'
      }
    ]
  }
}
  1. Create your Parent Component:
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.removeImage = (id) => {
      // write the function to remove image from this.state.images array using id
    }
    this.getImage = (id) => {
      // write the function to get image from this.state.images array using id 
    }
    this.state = {/* past step 2 here */}
  }

  render() {
    return (
      <div>
        <MyContext.Provider value={this.state}>
          <MyContext.Consumer>
            {({images}) => (
              <div className="list-image">
                {images.map((img) => {
                    return (<img 
                              imgId={img.id} 
                              src={img.url} 
                              height={img.height} 
                              width={img.width} alt="nothing"
                            />);
                  }
                }
              </div>
            }}
          </MyContext.Consumer>
        </MyContext.Provider>
      </div>
    );
  }

Like that you will be able to alter the this.state.imgaes list that will directly alter your render of images list.

Hope it's what you asked for ;)

Related