數據驅動, 根據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>
);
}
}複製代碼