数据驱动, 根据state或者props的变化 => 视图的变化, 之前的方式每每是直接操做 DOM 实现, 触发某事件使得元素移动代码相似如:html
=>
this.moveRight = () => {
this.left += 8;
this.draw();
}
this.draw = () => {
if(this.ele === null){
this.ele = document.createElement('img');
this.ele.src = this.url;
this.ele.style.width = this.width + 'px';
this.ele.style.height = this.height + 'px';
this.ele.style.position = 'absolute';
app.appendChild(this.ele);
}
this.ele.style.left = this.left + 'px';
this.ele.style.top = this.top + 'px';
};复制代码
如今就友好不少react
=>
this.moveRight = () => {
this.setState( preState => (
{
left: preState.left + 8
}
));
}
<ContraBG
left={left}
top={top}
status={status}
toward={toward}>
</ContraBG>复制代码
结构更清晰, 逐个书写须要渲染的组件, 能让人一目了然的知道游戏运行中加载的组件, 老的方式代码风格去渲染一个元素如git
=>
const plane = new ourplane();
plane.draw();复制代码
若是渲染的多告终构复杂了,阅读就会十分困难。如今的代码风格就可以一目了然的看到全部运行的组件github
=>
@observer
class InGame extends React.PureComponent<InGameProps, {}> {
render() {
const { store } = this.props;
return (
<InGameBG // 包裹组件负责渲染背景变化相关
store={store}>
<Contra // 玩家控制的角色组件
store={store}/>
<BulletsMap // 负责渲染子弹
store={store}/>
<EnemiesMap // 负责渲染敌方角色
store={store}/>
</InGameBG>
);
}
}复制代码
灵活性
前者类与类之间继承会灵活不少, 如typescript
飞机继承至飞行物 => 飞行物继承至动态物 => 动态物继承至某一特性物体复制代码
其中子弹也能够继承至飞行物使得飞行物等能够衍生更多子类。React中各组件只能继承至React.Component,可采用HOC高阶组件思想去渲染一系列具备类似性质的组件。如超级玛丽游戏中有许多的墙,它们具备类似的渲染逻辑,以及一些都会须要用到的方法, 能够经过写一个静态方块的高阶组件去生成, 可以更高效的管理代码。数组
=>
function WithStaticSquare<TOwnProps>(options: StaticSquareOption):ComponentDecorator<TOwnProps> {
return Component =>
class HocSquare extends React.Component<TOwnProps, HocSquareState> {
// xxx
render() {
const { styles, className } = this.state;
const passThroughProps: any = this.props;
const classNames = className ? `staticHocWrap ${className}` : "staticHocWrap";
const staticProps: WrappedStaticSquareUtils = {
changeBackground: this.changeBackground,
toTopAnimate: this.toTopAnimate
}; // 提供一些可能会用到的改变背景图的方法以及被撞时调用向上动画的方法
return (
<div
className={classNames}
style={styles}>
<Component
hoc={staticProps}
{...passThroughProps}/>
</div>
);
}
}
}复制代码
采用PureComponent某些组件须要这样写bash
=>
class Square extends React.PureComponent<SquareProps, {}> {
// xxx
}复制代码
其中就须要了解PureComponent。React.PureComponent是2016.06.29 React 15.3中发布。app
![]()
image
PureComponent改变了生命周期方法shouldComponentUpdate,而且它会自动检查组件是否须要从新渲染。这时,只有PureComponent检测到state或者props发生变化时,PureComponent才会调用render方法,可是这种检查只是浅计较这就意味着嵌套对象和数组是不会被比较的 更多信息
多采用组件去渲染, 对比两种方法函数
=>
// 方法1.
<InGameBG // 包裹组件负责渲染背景变化相关
store={store}>
<Contra // 玩家控制的角色组件
store={store}/>
<BulletsMap // 负责渲染子弹
store={store}/>
<EnemiesMap // 负责渲染敌方角色
store={store}/>
</InGameBG>
//方法2.
<InGameBG
store={store}>
<Contra
store={store}/>
<div>
{
bulletMap.map((bullet, index) => {
if ( bullet ) {
return (
<Bullet
key={`Bullet-${index}`}
{...bullet}
index={index}
store={store}/>
);
}
return null;
})
}
</div>
<EnemiesMap
store={store}/>
</InGameBG>复制代码
这两种方法的区别就是在于渲染子弹是否经过组件渲染仍是在父组件中直接渲染, 其中方法2的性能会有很大的问题, 当某个子弹变化时使得最大的容器从新渲染, 其中全部子组件也会去判断是否须要从新渲染,使得界面会出现卡顿。而方法1则只会在发生数据变化的子弹去渲染。性能
及时移除监听, 在组件卸载时须要移除该组件的事件监听, 时间函数等。如游戏开始组件
=>
class GameStart extends React.Component<GameStartProps, {}> {
constructor(props) {
super(props);
this.onkeydownHandle = this.onkeydownHandle.bind(this);
}
componentDidMount() {
this.onkeydown();
}
componentWillUnmount() {
this.destroy();
}
destroy(): void {
console.log("游戏开始! GameStart Component destroy ....");
window.removeEventListener("keydown", this.onkeydownHandle);
}
onkeydownHandle(e: KeyboardEvent): void {
const keyCode: KeyCodeType = e.keyCode;
const { store } = this.props;
const { updateGameStatus } = store;
switch ( keyCode ) {
case 72:
updateGameStatus(1);
break;
}
}
onkeydown(): void {
window.addEventListener("keydown", this.onkeydownHandle);
}
render() {
return (
<div className="gameStartWrap">
</div>
);
}
}复制代码