ReactJS-不同文件中的应用程序功能

时间:2018-08-10 19:55:27

标签: reactjs.net

我正在尝试制作基于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;
}

我应该如何进行?

1 个答案:

答案 0 :(得分:0)

是的,组织JS代码非常容易!使用模块。这是这样做的方法。

  1. 从文件导出功能

adders.js

export function addTwo (number) {
  return number + 2
}
  1. 然后使用它:

这可能在组件文件中:

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可以帮助您实现更容易推理的状态,但它本身并不能帮助您更好地组织代码。希望对您有所帮助!