无法读取 属性 of 'keys' of undefined,在 React 中处理事件
Cannot read property of 'keys' of undefined, Handling Events in React
我的目标是有一个按钮 运行 Javascript roshtimer()
并且还有 运行 命令可用的热键。例如,我希望我的用户可以选择单击屏幕上的按钮或按键盘上的 'r'。
我在这个问题上遇到了很多麻烦,因为我是 React 的新手。
class Timer extends Component {
constructor(props) {
super(props);
this.state = {
time: 0,
roshDead: false,
roshDeathTime: 0,
aegisExpireTime: 0,
roshRespawnTime1: 0,
roshRespawnTime2: 0,
start: 0,
isOn: false,
};
this.startTimer = this.startTimer.bind(this);
this.stopTimer = this.stopTimer.bind(this);
this.resetTimer = this.resetTimer.bind(this);
this.roshTimer = this.roshTimer.bind(this);
this.roshButton = React.createRef();
this.handleRoshHotkey = this.handleRoshHotkey.bind(this);
}
componentDidMount() {
document.addEventListener("keydown", this.handleRoshHotkey);
}
componentWillUnmount() {
document.removeEventListener("keydown", this.handleRoshHotkey);
}
handleRoshClick() {
console.log("button was clicked!");
this.roshTimer();
}
handleRoshHotkey = (e) => {
if (e.key === "r" || e.keyCode === 13) {
console.log("hotkey was pressed!");
this.roshTimer();
}
};
startTimer() {
...
}
stopTimer() {
...
}
resetTimer() {
...
}
roshTimer() {
//compute rosh timers
let roshDeathTime = this.state.time;
let newAegisExpire = this.state.time + 300000; //5 mins = 300000 milliseconds
let newRespTime1 = this.state.time + 480000; // 8 mins = 480000 milliseconds
let newRespTime2 = this.state.time + 660000; // 11 mins = 660000 milliseconds
this.setState({
roshDeathTime: this.state.time,
aegisExpireTime: newAegisExpire,
roshRespawnTime1: newRespTime1,
roshRespawnTime2: newRespTime2,
roshDead: true,
});
//format rosh timers
...
//log to console for my own sanity
console.log(roshDeathTime, newAegisExpire, newRespTime1, newRespTime2);
//copy to user's clipboard
navigator.clipboard.writeText(
newAegisExpire + " " + newRespTime1 + " " + newRespTime2
);
}
render() {
let start =
this.state.time == 0 ? (
<button onClick={this.startTimer}>start</button>
) : null;
let stop = this.state.isOn ? (
<button onClick={this.stopTimer}>stop</button>
) : null;
let reset =
this.state.time != 0 && !this.state.isOn ? (
<button class="red" onClick={this.resetTimer}>
reset
</button>
) : null;
let resume =
this.state.time != 0 && !this.state.isOn ? (
<button class="green" onClick={this.startTimer}>
resume
</button>
) : null;
let rosh = this.state.isOn ? (
<div className={this.state.focused ? "focused" : ""}>
<button
onClick={() => this.handleRoshClick()}
autoFocus
ref={(c) => (this._input = c)}
>
{" "}
Rosh died!{" "}
</button>
</div>
) : null;
return (
<div>
<h3>
Timer: {prettyMilliseconds(this.state.time, { colonNotation: true })}
</h3>
{start}
{resume}
{stop}
{reset}
<div ref={this.roshButton} autofocus onKeyDown={() => this.handleRoshHotkey()} tabIndex={1}>
{rosh}
</div>
</div>
);
}
}
export default Timer;
目前,我可以 运行 我的应用程序并向垃圾邮件发送“Rosh 死了!”按钮并查看预期的输出。如果我点击网页上的任何地方,我就可以使用热键来获得预期的输出。但是,如果我在手动单击按钮之前使用热键,应用程序会崩溃,我会收到
TypeError: Cannot read property 'key' of undefined
进一步说明我的问题在这里:
handleRoshHotkey = (e) => {
if (e.key === "r" || e.keyCode === 13){ <-------------
console.log("hotkey was pressed!");
this.roshTimer();
}
};
这是崩溃前的控制台日志示例:
button was clicked!
1134 "5:01" "8:01" "11:01"
button was clicked!
1878 "5:01" "8:01" "11:01"
hotkey as pressed!
4318 "5:04" "8:04" "11:04"
hotkey was pressed!
5338 "5:05" "8:05" "11:05"
button was clicked!
8142 "5:08" "8:08" "11:08"
Uncaught TypeError: Cannot read property 'key' of undefined
.
. //(hundreds of lines of traceback follow)
.
hotkey was pressed!
11194 "5:11" "8:11" "11:11"
谢谢!
您忘记通过活动:
<div ref={this.roshButton} autofocus onKeyDown={(e) => this.handleRoshHotkey(e)} tabIndex={1}>
{rosh}
</div>
但更好:
<div ref={this.roshButton} autofocus onKeyDown={this.handleRoshHotkey} tabIndex={1}>
{rosh}
</div>
这可能只是一条评论,但您没有在 onKeyDown={() => this.handleRoshHotkey()}
中传递事件。
由于函数已经绑定,只需传递 onKeyDown={this.handleRoshHotkey}
事件将通过管道传输。
两件事:
主要问题是当你渲染的时候,你正在做
onKeyDown={() => this.handleRoshHotkey()}
...它调用 handleRoshHotkey
时没有参数,这就是您收到错误的原因。由于您在构造函数中使用了 bind
,因此将其更改为:
onKeyDown={this.handleRoshHotkey}
在 React 中使用处理程序就足够了,您 也 不想通过 addEventListener
使用它,所以删除该代码(我'我猜你添加它是为了调试)。您可以完全删除 componentDidMount
和 componentWillUnmount
.
我的目标是有一个按钮 运行 Javascript roshtimer()
并且还有 运行 命令可用的热键。例如,我希望我的用户可以选择单击屏幕上的按钮或按键盘上的 'r'。
我在这个问题上遇到了很多麻烦,因为我是 React 的新手。
class Timer extends Component {
constructor(props) {
super(props);
this.state = {
time: 0,
roshDead: false,
roshDeathTime: 0,
aegisExpireTime: 0,
roshRespawnTime1: 0,
roshRespawnTime2: 0,
start: 0,
isOn: false,
};
this.startTimer = this.startTimer.bind(this);
this.stopTimer = this.stopTimer.bind(this);
this.resetTimer = this.resetTimer.bind(this);
this.roshTimer = this.roshTimer.bind(this);
this.roshButton = React.createRef();
this.handleRoshHotkey = this.handleRoshHotkey.bind(this);
}
componentDidMount() {
document.addEventListener("keydown", this.handleRoshHotkey);
}
componentWillUnmount() {
document.removeEventListener("keydown", this.handleRoshHotkey);
}
handleRoshClick() {
console.log("button was clicked!");
this.roshTimer();
}
handleRoshHotkey = (e) => {
if (e.key === "r" || e.keyCode === 13) {
console.log("hotkey was pressed!");
this.roshTimer();
}
};
startTimer() {
...
}
stopTimer() {
...
}
resetTimer() {
...
}
roshTimer() {
//compute rosh timers
let roshDeathTime = this.state.time;
let newAegisExpire = this.state.time + 300000; //5 mins = 300000 milliseconds
let newRespTime1 = this.state.time + 480000; // 8 mins = 480000 milliseconds
let newRespTime2 = this.state.time + 660000; // 11 mins = 660000 milliseconds
this.setState({
roshDeathTime: this.state.time,
aegisExpireTime: newAegisExpire,
roshRespawnTime1: newRespTime1,
roshRespawnTime2: newRespTime2,
roshDead: true,
});
//format rosh timers
...
//log to console for my own sanity
console.log(roshDeathTime, newAegisExpire, newRespTime1, newRespTime2);
//copy to user's clipboard
navigator.clipboard.writeText(
newAegisExpire + " " + newRespTime1 + " " + newRespTime2
);
}
render() {
let start =
this.state.time == 0 ? (
<button onClick={this.startTimer}>start</button>
) : null;
let stop = this.state.isOn ? (
<button onClick={this.stopTimer}>stop</button>
) : null;
let reset =
this.state.time != 0 && !this.state.isOn ? (
<button class="red" onClick={this.resetTimer}>
reset
</button>
) : null;
let resume =
this.state.time != 0 && !this.state.isOn ? (
<button class="green" onClick={this.startTimer}>
resume
</button>
) : null;
let rosh = this.state.isOn ? (
<div className={this.state.focused ? "focused" : ""}>
<button
onClick={() => this.handleRoshClick()}
autoFocus
ref={(c) => (this._input = c)}
>
{" "}
Rosh died!{" "}
</button>
</div>
) : null;
return (
<div>
<h3>
Timer: {prettyMilliseconds(this.state.time, { colonNotation: true })}
</h3>
{start}
{resume}
{stop}
{reset}
<div ref={this.roshButton} autofocus onKeyDown={() => this.handleRoshHotkey()} tabIndex={1}>
{rosh}
</div>
</div>
);
}
}
export default Timer;
目前,我可以 运行 我的应用程序并向垃圾邮件发送“Rosh 死了!”按钮并查看预期的输出。如果我点击网页上的任何地方,我就可以使用热键来获得预期的输出。但是,如果我在手动单击按钮之前使用热键,应用程序会崩溃,我会收到
TypeError: Cannot read property 'key' of undefined
进一步说明我的问题在这里:
handleRoshHotkey = (e) => {
if (e.key === "r" || e.keyCode === 13){ <-------------
console.log("hotkey was pressed!");
this.roshTimer();
}
};
这是崩溃前的控制台日志示例:
button was clicked!
1134 "5:01" "8:01" "11:01"
button was clicked!
1878 "5:01" "8:01" "11:01"
hotkey as pressed!
4318 "5:04" "8:04" "11:04"
hotkey was pressed!
5338 "5:05" "8:05" "11:05"
button was clicked!
8142 "5:08" "8:08" "11:08"
Uncaught TypeError: Cannot read property 'key' of undefined
.
. //(hundreds of lines of traceback follow)
.
hotkey was pressed!
11194 "5:11" "8:11" "11:11"
谢谢!
您忘记通过活动:
<div ref={this.roshButton} autofocus onKeyDown={(e) => this.handleRoshHotkey(e)} tabIndex={1}>
{rosh}
</div>
但更好:
<div ref={this.roshButton} autofocus onKeyDown={this.handleRoshHotkey} tabIndex={1}>
{rosh}
</div>
这可能只是一条评论,但您没有在 onKeyDown={() => this.handleRoshHotkey()}
中传递事件。
由于函数已经绑定,只需传递 onKeyDown={this.handleRoshHotkey}
事件将通过管道传输。
两件事:
主要问题是当你渲染的时候,你正在做
onKeyDown={() => this.handleRoshHotkey()}
...它调用
handleRoshHotkey
时没有参数,这就是您收到错误的原因。由于您在构造函数中使用了bind
,因此将其更改为:onKeyDown={this.handleRoshHotkey}
在 React 中使用处理程序就足够了,您 也 不想通过
addEventListener
使用它,所以删除该代码(我'我猜你添加它是为了调试)。您可以完全删除componentDidMount
和componentWillUnmount
.