代码之家  ›  专栏  ›  技术社区  ›  justDan

在react中将ref传递给父级

  •  0
  • justDan  · 技术社区  · 7 年前

    我有一个小应用程序,有一个输入,根据搜索值,显示特定城市的天气。但我在某一点上被卡住了。这个想法是,一旦你搜索一个城市,它会隐藏文本输入和搜索按钮,并显示一些天气信息和另一个搜索按钮来搜索一个新的城市。我的问题是,当我再次单击搜索时,我希望将注意力集中在搜索框上。我希望这是有道理的。我读到这样做的理想方式是 refs . 我是这样把它连接起来的:

    class WeatherForm extends React.Component {
      constructor(props) {
        super(props);
        this.city = React.createRef();
      }
    
      componentDidMount() {
        this.props.passRefUpward(this.city);
        this.city.current.focus();
      }
    
      render() {
        if (this.props.isOpen) {
          return (
            <div className={style.weatherForm}>
              <form action='/' method='GET'>
                <input 
                  ref={this.city} 
                  onChange={this.props.updateInputValue} 
                  type='text' 
                  placeholder='Search city' 
                />
                <input 
                  onClick={e => this.props.getWeather(e)} 
                  type='submit' 
                  value='Search' 
                /> 
              </form>
            </div>
          )
        } else {
          return (
            <div className={style.resetButton}>
              <p>Seach another city?</p>
              <button 
                onClick={this.props.resetSearch}>Search
              </button>
            </div>
          );
        }
      }
    }
    

    有了这个,我可以通过使用 this.state.myRefs.current.value; this.state.myRefs.current 在不同的功能中使用 .focus() ,它返回 null .

    resetSearch = () => {
        console.log(this.state.myRefs.current); // <- returns null
    
        this.setState({
          isOpen: !this.state.isOpen,
          details: [],
          video: []
        });
      }
    

    这是因为我根据搜索点击隐藏和显示不同的组件吗?我已经读了很多关于这个的帖子,但我仍然无法破解这个。感谢您的帮助。我将在下面包含完整的代码。要全面了解这一点,请参见git回购协议: https://github.com/DanDeller/tinyWeather/blob/master/src/components/WeatherMain.js

    class Weather extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          recentCities: [],
          details: [],
          isOpen: true,
          myRefs: '',
          video: '',
          city: ''
        };
    
        this.updateInputValue = this.updateInputValue.bind(this);
        this.getRefsFromChild = this.getRefsFromChild.bind(this);
        this.resetSearch = this.resetSearch.bind(this);
        this.getWeather = this.getWeather.bind(this);
      }
    
      updateInputValue = (e) => {
        ...
      }
    
      resetSearch = () => {
        console.log(this.state.myRefs.current);
    
        this.setState({
          isOpen: !this.state.isOpen,
          details: [],
          video: []
        });
      }
    
      getWeather = (e) => {
        ...
      }
    
      getRefsFromChild = (childRefs) => {
        ...
      }
    
      render() {
        return (
          <section className={style.container}>
            <div className={style.weatherMain + ' ' + style.bodyText}>
              <video key={this.state.video} className={style.video} loop autoPlay muted>
                <source src={this.state.video} type="video/mp4">
                </source>
                Your browser does not support the video tag.
              </video>
              <div className={style.hold}>
                <div className={style.weatherLeft}>
                  <WeatherForm
                    updateInputValue={this.updateInputValue}
                    getWeather={this.getWeather}
                    passRefUpward={this.getRefsFromChild}
                    resetSearch={this.resetSearch}
                    isOpen={this.state.isOpen}
    
                  />
                  <WeatherList
                    details={this.state.details}
                    city={this.state.city}
                    isOpen={this.state.isOpen}
                  />
                </div>
                <div className={style.weatherRight}>
                  <Sidebar
                    recentCities={this.state.recentCities}
                  />
                </div>
                <div className={style.clear}></div>
              </div>
            </div>
          </section>
        );
      }
    }
    
    
    class WeatherForm extends React.Component {
      constructor(props) {
        super(props);
        this.city = React.createRef();
      }
    
      componentDidMount() {
        this.props.passRefUpward(this.city);
        this.city.current.focus();
      }
    
      render() {
        if (this.props.isOpen) {
          return (
            <div className={style.weatherForm}>
              <form action='/' method='GET'>
                <input 
                  ref={this.city} 
                  onChange={this.props.updateInputValue} 
                  type='text' 
                  placeholder='Search city' 
                />
                <input 
                  onClick={e => this.props.getWeather(e)} 
                  type='submit' 
                  value='Search' 
                /> 
              </form>
            </div>
          )
        } else {
          return (
            <div className={style.resetButton}>
              <p>Seach another city?</p>
              <button 
                onClick={this.props.resetSearch}>Search
              </button>
            </div>
          );
        }
      }
    }
    
    export default Weather;
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   sdkcy    7 年前

    您试图从DOM中实现未安装的组件,因此无法捕获引用。如果将此代码替换为WeatherForm组件的渲染函数,则可以捕获引用。因为我只是隐藏它,而不是从DOM中删除它。

      render() {
            return (
                <div>
                    <div className={style.weatherForm}
                         style={this.props.isOpen ? {visibility:"initial"} :{visibility:"hidden"}}>
                        <form action='/' method='GET'>
                            <input
                                ref={this.city}
                                onChange={this.props.updateInputValue}
                                type='text'
                                placeholder='Search city'
                            />
                            <input
                                onClick={e => this.props.getWeather(e)}
                                type='submit'
                                value='Search'
                            />
                        </form>
                    </div>
                    <div className={style.resetButton} style={this.props.isOpen ? {visibility:"hidden"} :{visibility:"initial"}}>
                        <p>Seach another city?</p>
                        <button
                            onClick={this.props.resetSearch}>Search
                        </button>
                    </div>
                </div>
            )
       }
    
        2
  •  0
  •   Sahil Arora    7 年前

    console.log(this.state.myRefs.current)返回null,因为它是对输入dom元素的引用,该元素不存在,因为当前天气窗体正在显示搜索另一个城市以及重置按钮。

    重置功能状态发生变化,导致WeatherForm组件的支柱等参线发生变化。现在,屏幕将显示输入字段和搜索按钮。

    请在WeatherForm中添加ComponentDidUpdate生命周期方法并添加, 方法体中的this.city.current.focus()。

    编辑1:-

    仅当prop(isOpen)为true时,需要将输入字段设置为焦点,因为只有当其已安装时,我们才能获得输入字段的引用。

    ComponentDidUpdate(){
    if(this props.isOpen)
    this.city.current.focus
    }
    

    链接到生命周期方法:- https://reactjs.org/docs/react-component.html#componentdidupdate

    希望这有帮助,

    干杯