我正在尝试制作基于React的网络游戏。我有一个App组件,其中几乎包含所有非UX状态。为了避免代码重复,我还保留了其中的大多数功能,并将其作为道具传递给子组件。
但是现在我开始被App主体中的各种功能所困扰。有什么简单的方法可以在不同文件中满足要求的结构?我应该已经研究过状态管理库吗?
当前内容如下:
class App extends Component {
constructor(props) {
super(props);
this.state = gameInitialize();
this.modifyState = this.modifyState.bind(this);
this.moveUnit = this.moveUnit.bind(this);
this.progressMission = this.progressMission.bind(this);
this.timeJump = this.timeJump.bind(this);
this.competenceAfterTimeJump = this.competenceAfterTimeJump.bind(this);
this.save = this.save.bind(this);
this.load = this.load.bind(this);
}
componentDidMount() {
this.timerID = setInterval(this.modifyState, this.state.interval);
window.addEventListener('beforeunload', this.save);
this.load();
}
componentWillUnmount() {
clearInterval(this.timerID);
}
save() {
localStorage.setItem("gameSave", toJson(this.state));
}
load() {
let state = 0;
try {
state = fromJson(localStorage.getItem("gameSave"));
} catch (error) {
console.log(error);
return 0;
}
state.units.map(unit => {
delete unit.__parent;
delete unit.attributes.__parent
return 0;
});
state.missions.map(mission => delete mission.__parent);
this.setState(state);
}
modifyState() {
this.setState(this.state.units.map(this.progressMission));
this.setState(this.state);
}
progressMission(unit) {
const mission = unit.currentMission;
let increment = unit.attributes[mission.type].total() - mission.complexity;
if (increment < 0) increment = 0;
mission.progress += increment * this.state.interval / 1000 * unit.competence / 10;
if (mission.progress >= mission.difficulty) {
mission.progress = 0;
this.state.experience.get(mission.reward);
mission.completions += 1;
}
}
moveUnit(unit, mission) {
unit.currentMission = mission;
this.setState(this.state);
}
timeJump() {
const game = this.state;
while (game.units.length > 2) {
game.units.pop();
};
game.units.map(function (unit) {
Object.keys(unit.attributes).map((key) => { unit.attributes[key] = newAttribute() });
unit.currentMission = game.missions[0];
});
game.missions.map((mission) => {mission.progress = 0});
game.units[0].competence = this.competenceAfterTimeJump();
game.experience.current = 0;
this.setState(game);
}
competenceAfterTimeJump() {
return (10 + Math.sqrt(this.state.experience.total) / 10);
}
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="title">Time-traveling Hero: eventually I'll save the world, or maybe not if I don't feel it</h1>
</header>
<SaveLoad game={this} />
<Prestige game={this} />
<MissionWrapper>
<MissionList missions={this.state.missions} game={this} />
</MissionWrapper>
<UnitWrapper>
<ExpWrapper>
<div>
Available Experience: {this.state.experience.current.toFixed(1)}
</div>
<div>
Total Experience: {this.state.experience.total.toFixed(1)}
</div>
</ExpWrapper>
<UnitList units={this.state.units} game={this} />
</UnitWrapper>
</div>
);
}
}
function gameInitialize() {
let game = { units: [], missions: [], currentUnit: undefined };
game.interval = 10;
game.missions = generateMissions(50);
game.experience = {
current: 0, total: 0,
get: function (amount) { this.current += amount; this.total += amount },
spend: function (amount) {
if (this.current >= amount) {
this.current -= amount;
return true;
}
else return false;
}
};
game.units.push({ name: "Hero", attributes: newAttributes(), competence: 10, currentMission: game.missions[0] });
game.units.push({ name: "Childhood Friend", attributes: newAttributes(), competence: 15, currentMission: game.missions[0] });
game.currentUnit = game.units[0];
game.missionsWithUnits = function () {
this.missions.map()
}
return game;
}
我应该如何进行?
答案 0 :(得分:0)
是的,组织JS代码非常容易!使用模块。这是这样做的方法。
adders.js
:
export function addTwo (number) {
return number + 2
}
这可能在组件文件中:
import { addTwo } from './path/to/adders.js'
console.log(addTwo(5)) // logs 7
您可以在很多事情上组织得很好。如果您有一组相关功能,请使用这样的模块。这是文件结构:
mathStuff/
adders.js
index.js
您将所有相关文件都放在同一文件夹中,并且从上述单个文件中导出了功能。然后像这样设置索引:
index.js
:
import * as adders from './adders.js'
// Set up your object however you want.
const MathStuff = {
...adders
}
export default MathStuff
然后在任何组件中都可以执行以下操作:
import MathStuff from './path/to/mathStuff'
MathStuff.addTwo(7) // 9
对于更多的组织,您可以将索引设置为具有以下功能:
index.js
:
import * as adders from './adders.js'
import * as dividers from './dividers.js' // another math file with division functions or something
// Set up your object however you want.
const MathStuff = {
adders,
dividers
}
export default MathStuff
并像这样使用它:
import MathStuff from './path/to/mathStuff' // points to directory, NOT individual file
MathStuff.adders.addTwo(7) // 9
我绝对建议组织这样的代码。可改进的一件事是可测试性-测试纯函数而没有副作用非常容易。
我喜欢将数据库代码放在一个模块中,然后将其导入到任何地方以访问我的所有数据库功能。
我喜欢按类别将所有业务逻辑放在不同的模块中,例如GameLogic
之类。
这也将帮助您编写更多的功能代码。当前,您在单个函数中有很多状态修改-如果不将单个函数绑定到您的react组件的此上下文,就无法在模块中进行状态修改。相反,我建议将所有必需的参数传递给该函数,并使其返回一个值。这样可以消除业务逻辑,从而更易于管理状态。
例如,您的progressMission
函数访问this.state.interval
。您可以将interval
传递给函数本身。
我要注意的一件事是您的代码相互之间有很多依赖关系-函数通常必须访问其自身外部的许多内容,而不是独立的。尝试将其重构为模块化系统,可能会对您有很大帮助,在模块化系统中,函数要纯净得多-仅访问传递给它们的内容,并返回使用的值。使用上面的实际模块肯定可以做到这一点-我做的越多,代码就越好。它可以帮助您更好地推理代码。此外,一旦/开始实施测试,您会发现代码的所有复杂性使其很难进行测试-有很多副作用。
最后,在您的情况下,redux和外部状态管理可能无济于事,但它们可能会有所帮助。 Redux可以帮助您实现更容易推理的状态,但它本身并不能帮助您更好地组织代码。希望对您有所帮助!