重构组件 ReactJS
Refactoring a Component ReactJS
我是 React 的新手,我正在尝试制作一个简单的唱首歌游戏。现在一切都运行良好(在我看来),但我认为代码非常重复(我使用了很多 setState)。有人可以告诉我如何让它更干净并处理状态吗?我不会要求您为我重构此代码只是为了建议如何去做。感谢您的任何建议。
这是我的代码:
import React, { Component } from 'react';
class Enemy extends Component {
constructor(props) {
super(props);
this.state = {
hp: 10,
nextHp: 12,
clickDamage: 1,
gold: 0,
dps: 0.1,
num: 1,
tapCount: 0,
itemCount: 0,
tapCost: 10,
itemCost: 50
};
this.handleClick = this.handleClick.bind(this);
this.buyTap = this.buyTap.bind(this);
this.buyItem = this.buyItem.bind(this);
}
componentDidMount() {
const interval = setInterval(() => {
this.setState({ hp: this.state.hp -= this.state.dps });
if(this.state.hp <= 0) {
this.setState({ hp: this.state.hp = this.state.nextHp });
this.setState({ nextHp: Math.floor(this.state.nextHp * 1.2) })
this.setState({ gold: this.state.gold + 10});
this.setState({ num: Math.floor(Math.random() * 4 + 1)});
}
}, 100);
}
handleClick() {
this.setState({ hp: this.state.hp - this.state.clickDamage });
if(this.state.hp <= 0) {
this.setState({ hp: this.state.hp = this.state.nextHp });
this.setState({ nextHp: Math.floor(this.state.nextHp * 1.2) })
this.setState({ gold: this.state.gold + 10});
this.setState({ num: Math.floor(Math.random() * 4 + 1)});
}
}
buyTap() {
if (this.state.gold >= this.state.tapCost) {
this.setState({ gold: this.state.gold -= this.state.tapCost });
this.setState({ tapCount: this.state.tapCount += 1 });
this.setState({ clickDamage: this.state.clickDamage += 1 })
}
}
buyItem() {
if (this.state.gold >= this.state.itemCost) {
this.setState({ gold: this.state.gold -= this.state.itemCost });
this.setState({ itemCount: this.state.itemCount += 1 });
this.setState({ dps: this.state.dps += 0.1 });
}
}
render() {
return (
<div>
<div className="container ui center aligned">
<h1>Enemy hp: {Math.round(this.state.hp)}</h1>
<h3>Gold: {this.state.gold}</h3>
<h3>Click damage: {this.state.clickDamage}</h3>
<h3>Damage per second: {Math.round(this.state.dps * 10)}</h3>
<img
alt=""
className="dragon"
src={require("../img/dragon" + this.state.num + ".jpg")}
onClick={this.handleClick}
draggable={false}
/>
</div>
<div className="ui container">
<img
onClick={this.buyTap}
alt=""
style={{ width: '50px' }}
src={require("../img/tap.png")}
/>
<p>Count: {this.state.tapCount}</p>
<p>Cost: {this.state.tapCost}</p>
<img
onClick={this.buyItem}
alt=""
style={{ width: '50px' }}
src={require("../img/rapier.png")}
/>
<p>Count: {this.state.itemCount}</p>
<p>Cost: {this.state.itemCost}</p>
</div>
</div>
);
}
}
export default Enemy;
没什么可考虑的。但我可以说你所有的状态更新都可以合并。您可以一次更新多个状态值。
this.setState({ hp: this.state.hp = this.state.nextHp });
this.setState({ nextHp: Math.floor(this.state.nextHp * 1.2) })
this.setState({ gold: this.state.gold + 10});
this.setState({ num: Math.floor(Math.random() * 4 + 1)});
至
this.setState({
hp: this.state.nextHp,
nextHp: Math.floor(this.state.nextHp * 1.2),
gold: this.state.gold + 10,
num: Math.floor(Math.random() * 4 + 1)
});
旁注:像this.state.hp = this.state.nextHp
这样的状态突变是一种反应反模式,可能会导致错误。
第二个旁注:对于依赖于当前状态值的状态更新,最好使用功能状态更新,以便在以下情况下正确排队和处理状态更新在一个渲染周期中触发多个更新。
this.setState(prevState => ({
hp: prevState.nextHp,
nextHp: Math.floor(prevState.nextHp * 1.2),
gold: prevState.gold + 10,
num: Math.floor(Math.random() * 4 + 1)
}));
这是我的 codesandbox demo 说明为什么此功能更新 很重要。
除了像@Drew Reese 的回答那样将 setState
组合成一个,您还可以通过在class:
handleClick = () => {
// ...
}
buyTap = () => {
// ...
}
buyItem = () => {
// ...
}
这样,您还可以从
中删除构造函数
constructor(props) {
super(props);
this.state = {
hp: 10,
nextHp: 12,
clickDamage: 1,
gold: 0,
dps: 0.1,
num: 1,
tapCount: 0,
itemCount: 0,
tapCost: 10,
itemCost: 50
};
this.handleClick = this.handleClick.bind(this);
this.buyTap = this.buyTap.bind(this);
this.buyItem = this.buyItem.bind(this);
}
只是
// (state is defined without a constructor as an instance variable)
state = {
hp: 10,
nextHp: 12,
clickDamage: 1,
gold: 0,
dps: 0.1,
num: 1,
tapCount: 0,
itemCount: 0,
tapCost: 10,
itemCost: 50
};
我是 React 的新手,我正在尝试制作一个简单的唱首歌游戏。现在一切都运行良好(在我看来),但我认为代码非常重复(我使用了很多 setState)。有人可以告诉我如何让它更干净并处理状态吗?我不会要求您为我重构此代码只是为了建议如何去做。感谢您的任何建议。
这是我的代码:
import React, { Component } from 'react';
class Enemy extends Component {
constructor(props) {
super(props);
this.state = {
hp: 10,
nextHp: 12,
clickDamage: 1,
gold: 0,
dps: 0.1,
num: 1,
tapCount: 0,
itemCount: 0,
tapCost: 10,
itemCost: 50
};
this.handleClick = this.handleClick.bind(this);
this.buyTap = this.buyTap.bind(this);
this.buyItem = this.buyItem.bind(this);
}
componentDidMount() {
const interval = setInterval(() => {
this.setState({ hp: this.state.hp -= this.state.dps });
if(this.state.hp <= 0) {
this.setState({ hp: this.state.hp = this.state.nextHp });
this.setState({ nextHp: Math.floor(this.state.nextHp * 1.2) })
this.setState({ gold: this.state.gold + 10});
this.setState({ num: Math.floor(Math.random() * 4 + 1)});
}
}, 100);
}
handleClick() {
this.setState({ hp: this.state.hp - this.state.clickDamage });
if(this.state.hp <= 0) {
this.setState({ hp: this.state.hp = this.state.nextHp });
this.setState({ nextHp: Math.floor(this.state.nextHp * 1.2) })
this.setState({ gold: this.state.gold + 10});
this.setState({ num: Math.floor(Math.random() * 4 + 1)});
}
}
buyTap() {
if (this.state.gold >= this.state.tapCost) {
this.setState({ gold: this.state.gold -= this.state.tapCost });
this.setState({ tapCount: this.state.tapCount += 1 });
this.setState({ clickDamage: this.state.clickDamage += 1 })
}
}
buyItem() {
if (this.state.gold >= this.state.itemCost) {
this.setState({ gold: this.state.gold -= this.state.itemCost });
this.setState({ itemCount: this.state.itemCount += 1 });
this.setState({ dps: this.state.dps += 0.1 });
}
}
render() {
return (
<div>
<div className="container ui center aligned">
<h1>Enemy hp: {Math.round(this.state.hp)}</h1>
<h3>Gold: {this.state.gold}</h3>
<h3>Click damage: {this.state.clickDamage}</h3>
<h3>Damage per second: {Math.round(this.state.dps * 10)}</h3>
<img
alt=""
className="dragon"
src={require("../img/dragon" + this.state.num + ".jpg")}
onClick={this.handleClick}
draggable={false}
/>
</div>
<div className="ui container">
<img
onClick={this.buyTap}
alt=""
style={{ width: '50px' }}
src={require("../img/tap.png")}
/>
<p>Count: {this.state.tapCount}</p>
<p>Cost: {this.state.tapCost}</p>
<img
onClick={this.buyItem}
alt=""
style={{ width: '50px' }}
src={require("../img/rapier.png")}
/>
<p>Count: {this.state.itemCount}</p>
<p>Cost: {this.state.itemCost}</p>
</div>
</div>
);
}
}
export default Enemy;
没什么可考虑的。但我可以说你所有的状态更新都可以合并。您可以一次更新多个状态值。
this.setState({ hp: this.state.hp = this.state.nextHp });
this.setState({ nextHp: Math.floor(this.state.nextHp * 1.2) })
this.setState({ gold: this.state.gold + 10});
this.setState({ num: Math.floor(Math.random() * 4 + 1)});
至
this.setState({
hp: this.state.nextHp,
nextHp: Math.floor(this.state.nextHp * 1.2),
gold: this.state.gold + 10,
num: Math.floor(Math.random() * 4 + 1)
});
旁注:像this.state.hp = this.state.nextHp
这样的状态突变是一种反应反模式,可能会导致错误。
第二个旁注:对于依赖于当前状态值的状态更新,最好使用功能状态更新,以便在以下情况下正确排队和处理状态更新在一个渲染周期中触发多个更新。
this.setState(prevState => ({
hp: prevState.nextHp,
nextHp: Math.floor(prevState.nextHp * 1.2),
gold: prevState.gold + 10,
num: Math.floor(Math.random() * 4 + 1)
}));
这是我的 codesandbox demo 说明为什么此功能更新 很重要。
除了像@Drew Reese 的回答那样将 setState
组合成一个,您还可以通过在class:
handleClick = () => {
// ...
}
buyTap = () => {
// ...
}
buyItem = () => {
// ...
}
这样,您还可以从
中删除构造函数 constructor(props) {
super(props);
this.state = {
hp: 10,
nextHp: 12,
clickDamage: 1,
gold: 0,
dps: 0.1,
num: 1,
tapCount: 0,
itemCount: 0,
tapCost: 10,
itemCost: 50
};
this.handleClick = this.handleClick.bind(this);
this.buyTap = this.buyTap.bind(this);
this.buyItem = this.buyItem.bind(this);
}
只是
// (state is defined without a constructor as an instance variable)
state = {
hp: 10,
nextHp: 12,
clickDamage: 1,
gold: 0,
dps: 0.1,
num: 1,
tapCount: 0,
itemCount: 0,
tapCost: 10,
itemCost: 50
};