3

I am having a parent component and a child component. I want to call a function from my child in my parent component. I am using ref and it works fine, but just for my last element in my array...

Parent:

onClick = () => {
  this.child.handleClose(); // do stuff
};

var items = [];
tracks.filter(searchingFor(term)).map(function (title, i) {
  items.push(
    <div>
      <ItemViewAll
        onRef={(ref) => (this.child = ref)}
        triggerOpen={this.handleOpenParent.bind(this)}
        triggerClose={this.handleCloseParent.bind(this)}
        key={title.id}
        title={title.title}
      />
    </div>
  );
}, this);

ItemViewAll is imported from my Child component, where the needed functions are located.

Child:

componentDidMount() {
    this.props.onRef(this)    
}

componentWillUnmount() {
    this.props.onRef(undefined)
}
    
handleClose = () => {
    this.setState({ open: false });
    this.props.triggerClose();
}

It seems like that the ref works only for the last element in my items[]...

Do you have any suggestions on how to make it work for every element in my array?

Here is my full Parent Compoenent, could be heldpful. Still have no clue how to set the ref...

Parent (complete):

const { scaleDown } = transitions;

function searchingFor(term) {
  return function (x) {
    return (
      x.title.toLowerCase().includes(term.toLowerCase()) ||
      x.body.toLowerCase().includes(term.toLowerCase())
    );
  };
}

class ViewAll extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      term: "",
      mounted: false,
      tracks: [],
      hasMoreItems: true,
    };

    this.searchHandler = this.searchHandler.bind(this);
    this.focus = this.focus.bind(this);
  }

  loadContent() {
    var requestUrl = this.props.url;
    fetch(requestUrl)
      .then((response) => {
        return response.json();
      })
      .then((tracks) => {
        this.setState({ tracks: this.state.tracks.concat(tracks) });
      })
      .catch((err) => {
        console.log("There has been an error");
      });
  }

  componentDidMount() {
    var requestUrl = this.props.url;
    fetch(requestUrl)
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        this.setState({ tracks: data });
      })
      .catch((err) => {
        console.log("There has been an error");
      });
    window.scrollTo(0, 0);
    this.focus();
  }

  handleOpenParent() {
    this.setState({ show: true });
  }

  handleCloseParent() {
    this.setState({ show: false });
  }

  searchHandler(event) {
    this.setState({ term: event.target.value });
  }

  focus() {
    this.textInput.focus();
  }

  onClick = () => {
    this.child.handleClose(); // do stuff
  };

  render() {
    const { term, data, tracks } = this.state;

    const loader = <div className="loader"></div>;

    var items = [];
    tracks.filter(searchingFor(term)).map(function (title, i) {
      items.push(
        <div>
          <MuiThemeProvider>
            <Paper
              style={{
                borderRadius: "2em",
                background:
                  "linear-gradient(to right, #82f2da 30%, white 100%)",
              }}
              zDepth={1}
            >
              <ItemViewAll
                onRef={(ref) => (this.child = ref)}
                triggerOpen={this.handleOpenParent.bind(this)}
                triggerClose={this.handleCloseParent.bind(this)}
                key={title.id}
                title={title.title}
                score={title.vote_average}
                overview={title.body}
                backdrop={title.image}
                description={title.description}
                messenger={title.messenger}
                twitter={title.twitter}
                discord={title.discord}
                slack={title.slack}
                kik={title.kik}
                telegram={title.telegram}
              />
            </Paper>
          </MuiThemeProvider>
        </div>
      );
    }, this);

    return (
      <div>
        <header className="Header">
          {this.state.show && (
            <div
              style={{ height: 50, width: 50, background: "red" }}
              onClick={this.onClick}
            ></div>
          )}
        </header>

        <div>
          <Media query="(max-width: 599px)">
            {(matches) =>
              matches ? (
                <div style={{ marginTop: 100 }}>
                  <div
                    style={{
                      width: "90%",
                      marginLeft: "auto",
                      marginRight: "auto",
                      marginBottom: 50,
                    }}
                  >
                    <MuiThemeProvider>
                      <TextField
                        hintText="Welcher Bot darf es sein?"
                        type="Text"
                        onChange={this.searchHandler}
                        value={term}
                        fullWidth={true}
                        underlineFocusStyle={{
                          borderColor: "#82f2da",
                          borderWidth: 3,
                        }}
                        underlineStyle={{
                          borderColor: "#82f2da",
                          borderWidth: 1.5,
                          top: "40px",
                        }}
                        hintStyle={{ fontSize: 30, fontFamily: "Anton" }}
                        inputStyle={{ fontSize: 30, fontFamily: "Anton" }}
                        ref={(input) => {
                          this.textInput = input;
                        }}
                        style={{ caretColor: "#82f2da" }}
                      />
                    </MuiThemeProvider>
                  </div>
                </div>
              ) : (
                <div style={{ marginTop: 130 }}>
                  <div
                    style={{
                      width: "80%",
                      marginLeft: "auto",
                      marginRight: "auto",
                      marginBottom: 70,
                    }}
                  >
                    <MuiThemeProvider>
                      <TextField
                        hintText="Welcher Bot darf es sein?"
                        type="Text"
                        onChange={this.searchHandler}
                        value={term}
                        fullWidth={true}
                        underlineFocusStyle={{
                          borderColor: "#82f2da",
                          borderWidth: 3,
                        }}
                        underlineStyle={{
                          borderColor: "#82f2da",
                          borderWidth: 1.5,
                          top: "50px",
                        }}
                        hintStyle={{ fontSize: 40, fontFamily: "Anton" }}
                        inputStyle={{ fontSize: 40, fontFamily: "Anton" }}
                        ref={(input) => {
                          this.textInput = input;
                        }}
                        style={{ caretColor: "#82f2da" }}
                      />
                    </MuiThemeProvider>
                  </div>
                </div>
              )
            }
          </Media>

          <Media query="(max-width: 599px)">
            {(matches) =>
              matches ? (
                <InfiniteScroll
                  pageStart={1}
                  loadMore={this.loadContent.bind(this)}
                  hasMore={this.state.hasMoreItems}
                  loader={loader}
                  initialLoad={false}
                >
                  <StackGrid
                    columnWidth={180}
                    gutterHeight={10}
                    gutterWidth={10}
                    duration={1500}
                    monitorImagesLoaded={true}
                    easing={easings.quadInOut}
                    appear={scaleDown.appear}
                    appeared={scaleDown.appeared}
                    enter={scaleDown.enter}
                    entered={scaleDown.entered}
                    leaved={scaleDown.leaved}
                  >
                    {items}
                  </StackGrid>
                </InfiniteScroll>
              ) : (
                <InfiniteScroll
                  pageStart={10}
                  loadMore={this.loadContent.bind(this)}
                  hasMore={this.state.hasMoreItems}
                  loader={loader}
                  initialLoad={true}
                >
                  <StackGrid
                    columnWidth={180}
                    gutterHeight={80}
                    gutterWidth={80}
                    duration={1500}
                    monitorImagesLoaded={true}
                    easing={easings.quadInOut}
                    appear={scaleDown.appear}
                    appeared={scaleDown.appeared}
                    enter={scaleDown.enter}
                    entered={scaleDown.entered}
                    leaved={scaleDown.leaved}
                  >
                    {items}
                  </StackGrid>
                </InfiniteScroll>
              )
            }
          </Media>
        </div>
      </div>
    );
  }
}

export default ViewAll;

The onClick function schould be called when clicked on the div in my header. But for all elements in my array and not just for the last one.... The onClick function calls again the handleClose() in my Child.

1
  • I have the same issue, did you find any solution for this? Commented Sep 6, 2019 at 14:20

2 Answers 2

3

I believe the reason you always get the last element instance, it is because you are iterating an array and for every item, you render a new and overwrite the this.child variable with a new reference of .

But even though, you should not create a ref for each item of element. If you want to get the onClick event, you have to implement this event on the component . If the component is from a third party library, check the documentation to see how to handle events. Usually, it is with onClick event.

Sign up to request clarification or add additional context in comments.

Comments

0

hard to say for sure without seeing more of parent component code (i think you may have cut something from that accidentally), so it's just a guess, but you are probably overwriting your ref while mapping over array, hence it's working only for last element. you can find some solutions for that here.

1 Comment

Thanks for you answer, I added my full Parent Component to my post. Is it helpful for you?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.