React中如何向子组件传递ref?解决react-swipe实例调用异常
兄弟,我之前也踩过这个react-swipe ref传递的坑!你现在遇到的问题核心是拆分组件后,ref的传递方式不对,导致父组件拿不到react-swipe的实例,所以调用prev()/next()才会报“不是函数”的错。
先说说你原来写法的问题
你在拆分后的PlanetInfo组件里写了ref={this.swipeRef},但这里的this.swipeRef根本没被正确赋值——你把父组件传过来的swipeRef props当成了组件自身的属性,实际上子组件里应该直接使用props中的回调函数,而不是this.swipeRef(如果是函数组件的话甚至连this都没有)。
方案一:直接传递ref回调props
这是最直接的修改方式,只需要调整PlanetInfo组件的代码,把父组件传过来的swipeRef props直接绑定到ReactSwipe的ref上:
如果是函数组件版本的PlanetInfo
const PlanetInfo = ({ planetData, swipeRef }) => { const singlePlanets = planetData.map(data => ( <div className="single-planet" key={data.id}> <div className="image"> <img src={emptyPlanet} alt={data.name} /> </div> <h2>{data.name}</h2> <div className="extract" dangerouslySetInnerHTML={{ __html: data.extract }} /> </div> )); return ( <ReactSwipe ref={swipeRef} className="content" key={singlePlanets.length}> {singlePlanets} </ReactSwipe> ); };
如果是类组件版本的PlanetInfo
class PlanetInfo extends React.Component { render() { const { planetData, swipeRef } = this.props; const singlePlanets = planetData.map(data => ( <div className="single-planet" key={data.id}> <div className="image"> <img src={emptyPlanet} alt={data.name} /> </div> <h2>{data.name}</h2> <div className="extract" dangerouslySetInnerHTML={{ __html: data.extract }} /> </div> )); return ( <ReactSwipe ref={swipeRef} className="content" key={singlePlanets.length}> {singlePlanets} </ReactSwipe> ); } }
这样修改后,父组件里的swipeRef回调就能正确拿到react-swipe的实例,_handlePrev和_handleNext里的this.reactSwipe.prev()/next()就能正常调用了。
方案二:使用React.forwardRef(更推荐的规范写法)
如果你的PlanetInfo是函数组件,官方更推荐用forwardRef来透传ref,这种方式更清晰,也符合React的ref传递最佳实践:
修改PlanetInfo组件
const PlanetInfo = React.forwardRef(({ planetData }, ref) => { const singlePlanets = planetData.map(data => ( <div className="single-planet" key={data.id}> <div className="image"> <img src={emptyPlanet} alt={data.name} /> </div> <h2>{data.name}</h2> <div className="extract" dangerouslySetInnerHTML={{ __html: data.extract }} /> </div> )); // 把父组件传入的ref直接绑定到ReactSwipe上 return ( <ReactSwipe ref={ref} className="content" key={singlePlanets.length}> {singlePlanets} </ReactSwipe> ); });
父组件调用方式调整
<PlanetInfo planetData={this.state.planetData} ref={reactSwipe => this.reactSwipe = reactSwipe} />
这里不需要再用swipeRef这个自定义props了,直接用React原生的ref属性即可,更符合组件的使用习惯。
最后验证一下
不管用哪种方案,只要确保父组件的this.reactSwipe能拿到react-swipe的实例,调用prev()和next()就不会再报错了。你可以在_handlePrev里加个console.log(this.reactSwipe),看看是不是能打印出react-swipe的实例对象,这样就能快速验证是否成功了。
内容的提问来源于stack exchange,提问作者MyNotes

