Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reactjs ref only works for last element in array

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.

like image 326
Martin Seubert Avatar asked Sep 22 '26 13:09

Martin Seubert


1 Answers

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.

like image 170
aquilesb Avatar answered Sep 24 '26 15:09

aquilesb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!