reactjs ref仅适用于数组中的最后一个元素

时间:2018-11-08 16:33:41

标签: arrays reactjs parent-child ref

我有一个父组件和一个子组件。我想在我的父组件中从我的孩子那里调用一个函数。我正在使用ref,并且工作正常,但仅用于数组中的最后一个元素...

父母:

 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从我的Child组件(所需功能所在的位置)中导入。

孩子:

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

}
   componentWillUnmount() {
   this.props.onRef(undefined)
}

 handleClose = () => {

   this.setState({ open: false });
   this.props.triggerClose();

 };

似乎ref仅适用于我项目中的最后一个元素[] ...

您对如何使其适用于数组中的每个元素有任何建议?

这是我完整的家长资料,可以保留。仍然不知道如何设置参考...

父母(完整):

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;

在我的标题中的div上单击时,应调用onClick函数。但是对于我数组中的所有元素,而不仅仅是最后一个元素。...onClick函数再次调用Child中的handleClose()。

2 个答案:

答案 0 :(得分:1)

我相信总是得到最后一个元素实例的原因是,因为您正在迭代一个数组,并且对于每个项目,您都会渲染一个新的并使用。的新引用覆盖this.child变量。

但是,尽管如此,您也不应该为元素的每个项目创建一个引用。如果要获取onClick事件,则必须在component上实现此事件。如果该组件来自第三方库,请查看文档以了解如何处理事件。通常,它与onClick事件有关。

答案 1 :(得分:0)

很难确定而没有看到更多的父组件代码(我认为您可能不小心从中切出了一些东西),所以这只是一个猜测,但是您可能会在映射到数组时覆盖您的ref,因此它只能工作最后一个元素。您可以找到关于该here的一些解决方案。