React Dropzone:如何用this替代props作为参数传递?
为啥把params换成this就报错?咱们一步步搞懂
首先得说清楚你原来的代码为啥能正常运行:
- 在
Space组件里,你给onDrop绑定了当前组件的实例:onDrop: this.onDrop.bind(this),这就把onDrop内部的this钉死在了Space实例上,后面调用setState肯定没问题。 - 到了
MyDropzone这个函数组件里,你写了props.onDrop.bind(this),但函数组件本身没有自己的this(React严格模式下就是undefined),不过好在之前已经给onDrop绑定过Space的this了,bind(undefined)不会改变原函数的this指向,所以实际调用时onDrop内部的this还是Space实例,代码自然能正常运行。
那换成传this之后为啥炸了?核心有两个问题:
onDrop没绑定正确的this:直接传this给MyDropzone,相当于把Space的实例整个当props传进去。这时候props.onDrop是没绑定过的原始方法,你在MyDropzone里写props.onDrop.bind(this),这里的this是函数组件的undefined,绑定之后onDrop内部的this就变成undefined了,调用setState肯定报错——毕竟undefined哪来的setState方法啊!- 传组件实例本身就不规范:React组件的
props应该是明确的属性集合,直接传整个组件实例会把一堆内部属性(比如state、refs、React内置方法)都带过去,很容易引发各种意料之外的副作用,绝对是不推荐的写法。
怎么修复?给你几个方案
方案1:保持明确的props传递(最推荐)
别直接传this,继续传明确的属性集合,还能优化绑定写法避免重复绑定:
class Space extends Component { constructor(){ super(); // 提前在构造函数里绑定一次,不用每次render都重新bind this.onDrop = this.onDrop.bind(this); } onDrop(){ this.setState({/* 这里写你要更新的状态 */}); } render() { const params = { onDrop: this.onDrop }; return( <div>{MyDropzone(params)}</div> ); } } // MyDropzone里不用再bind,直接用props.onDrop就行 const MyDropzone = props =>( <div> <Dropzone onDrop={props.onDrop}> {/* 这里放你的Dropzone内容 */} </Dropzone> </div> )
方案2:如果非要传实例(不推荐)
要是真的有特殊需求必须传this,那得手动把onDrop绑定到Space实例上:
class Space extends Component { constructor(){super()} onDrop(){this.setState({/* 更新状态 */})} render() { return( <div>{MyDropzone(this)}</div> ); } } const MyDropzone = props =>( // 这里的props是Space实例,所以bind(props)来绑定正确的this <div><Dropzone onDrop={props.onDrop.bind(props)}> ... </Dropzone></div> )
额外优化:用箭头函数省掉绑定步骤
你还可以用类字段箭头函数,自动帮你绑定this,连构造函数里的绑定代码都省了:
class Space extends Component { // 箭头函数自动绑定当前组件实例的this onDrop = () => { this.setState({/* 更新的状态 */}); } render() { return( <div><MyDropzone onDrop={this.onDrop} /></div> ); } } const MyDropzone = ({ onDrop }) =>( <div><Dropzone onDrop={onDrop}> ... </Dropzone></div> )
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

