我在这个上下文问题上遇到了麻烦:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class Foo extends Component {
constructor(props) {
super(props)
this.state = {
error: false
}
}
render() {
const { handleChange } = this.props;
let _handleChange = handleChange.bind(this);
return (
<div>
<input type='file' onChange={_handleChange} id='input'/>
<label htmlFor='input'> Upload </label>
{this.state.error && <span>{this.state.errorMessage}</span>}
</div>
)
}
}
class FooClosure extends Component {
handleChange = (event) => {
let self = this // this will always be FooClosure
debugger // local this context will be Foo
this.setState({ error: true, errorMessage: 'Some error happened'})
}
render() {
return (
<div>
<Foo handleChange={this.handleChange} />
</div>
)
}
}
class App extends Component {
render() {
return (
<div className="App">
<FooClosure />
</div>
);
}
}
export default App;
我正在父组件中定义的函数内部尝试setState,该组件在子组件中被绑定。我对Javascript的理解意味着this
将成为子组件,但this.setState
总是在FooClosure的上下文中执行。谁能帮我理解为什么会这样?
我可以通过定义handleChange = (event, self) => ...
来轻松解决这个问题,但我认为我不应该这样做。
答案 0 :(得分:1)
这就是你应该写它的方式。
class Foo extends Component {
render() {
return (
<div>
<input type='file' onChange={this.props.handleChange} id='input'/>
<label htmlFor='input'> Upload </label>
{this.props.error && <span>{this.props.errorMessage}</span>}
</div>
)
}
}
class FooClosure extends Component {
constructor(props) {
super(props);
this.state = {error: false, errorMessage: ''};
}
handleChange = (event) => {
this.setState({ error: true, errorMessage: 'Some error happened'})
}
render() {
return (
<div>
<Foo handleChange={this.handleChange.bind(this)} error={this.state.error} errorMessage={this.state.errorMessage} />
</div>
)
}
}
答案 1 :(得分:0)
当您在this
方法中定义handleChange
时,您明确告诉程序要查看其正在编写函数的当前范围。将其作为道具传递只会在其书面范围内运行该功能,而不是重新定义this
,也不会在Foo
课程中重新定义该功能。
想象一下FooClosure
和Foo
在两个独立的房间里,不知何故变成众生。 FooClosure
有能力制作比萨饼。 Foo
能够致电FooClosure
并要求制作比萨饼。这里的问题是Foo
要求FooClosure
制作披萨,但是所有的配料和唯一的工作烤箱都在Foo
的房间里。
在这种情况下,最好的办法是将handleChange
方法转移到Foo
课程中,以便this
可以引用Foo
而不是FooClosure
反过来允许您设置Foo
的状态。
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class Foo extends Component {
constructor(props) {
super(props)
this.state = {
error: false
}
}
handleChange = event => {
this.setState({
error: true,
errorMessage: 'Some error happened',
})
}
render() {
const { handleChange } = this
return (
<div>
<input type='file' onChange={handleChange} id='input'/>
<label htmlFor='input'> Upload </label>
{this.state.error && <span>{this.state.errorMessage}</span>}
</div>
)
}
}
class FooClosure extends Component {
render() {
return (
<div>
<Foo />
</div>
)
}
}
class App extends Component {
render() {
return (
<div className="App">
<FooClosure />
</div>
);
}
}
export default App;
现在这当然会使你的FooClosure
课程变得多余。如果你需要根据Foo
中的onChange来处理任何事情,你可以使用它:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class Foo extends Component {
constructor(props) {
super(props)
this.state = {
error: false
}
}
handleChange = event => {
const { handleFooClosureMethod } = this.props.handleFooClosureMethod
handleFooClosureMethod(args)
this.setState({
error: true,
errorMessage: 'Some error happened',
})
}
render() {
const { handleChange } = this
return (
<div>
<input type='file' onChange={handleChange} id='input'/>
<label htmlFor='input'> Upload </label>
{this.state.error && <span>{this.state.errorMessage}</span>}
</div>
)
}
}
class FooClosure extends Component {
handleChange = args => {
//handle this method
}
render() {
return (
<div>
<Foo handleFooClosureMethod={this.handleChange} />
</div>
)
}
}
class App extends Component {
render() {
return (
<div className="App">
<FooClosure />
</div>
);
}
}
export default App;
请记住,每次在Foo
课程中发生onChange事件时,后者都会触发。
答案 2 :(得分:0)
这很有帮助,但并不完全准确。问题在于,通过绑定它或将其建立为匿名函数,它不能反弹到Foo的新上下文。
class Foo extends Component {
constructor(props) {
super(props)
this.state = {
error: false
}
this.handleChange = this.props.handleChange.bind(this)
debugger
}
render() {
console.log('foo state', this.state)
return (
<div>
<input type='file' onChange={this.handleChange} id='input'/>
<label htmlFor='input'> Upload </label>
{this.state.error && <span>{this.state.errorMessage}</span>}
</div>
)
}
}
class FooClosure extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange;
}
handleChange() {
let self = this // this will now be Foo
debugger // local this context will be Foo
this.setState({ error: true, errorMessage: 'Some error happened'})
}
render() {
console.log('closure state', this.state)
return (
<div>
<Foo handleChange={this.handleChange} />
</div>
)
}
}