【问题标题】:reactjs ref only works for last element in arrayreactjs ref 仅适用于数组中的最后一个元素
【发布时间】:2019-04-12 05:17:10
【问题描述】:

我有一个父组件和一个子组件。我想在我的父组件中从我的孩子调用一个函数。我正在使用 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 仅适用于我的 items[] 中的最后一个元素...

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

这是我完整的父组件,可以保存。仍然不知道如何设置参考...

家长(完整):

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()。

【问题讨论】:

  • 我也有同样的问题,请问您找到解决方法了吗?

标签: arrays reactjs parent-child ref


【解决方案1】:

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

但即便如此,您也不应该为每个元素项创建一个 ref。如果要获取 onClick 事件,则必须在组件上实现该事件。如果组件来自第三方库,请查看文档以了解如何处理事件。通常是onClick事件。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 感谢您的回答,我已将完整的父组件添加到我的帖子中。对你有帮助吗?
    猜你喜欢
    • 2012-03-11
    • 1970-01-01
    • 2020-07-09
    • 1970-01-01
    • 2018-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多