入门教程demo完成总结:
看了一下午,晚上又瞟了几眼,终于把井字棋的教程看完了,因此做一些总结。
一、使用slice()方法浅拷贝数组。
教程里有个slice()快速拷贝数组的方法。
const squares = this.state.squares.slice()
以前倒是没特意留意这些。
虽然也比较简单,但是发现这样拷贝出来的结果仅仅只是浅拷贝。
类似的还有arr.concat(),一样是浅拷贝。
二、不含有state的组件可以写成函数组件,避免class组件的繁琐。
三、状态提升和组件重构。
在学习过程中,组件经历了几次状态提升。
均是为了满足需求而一步步重构而来。
这种思路,我觉得挺有意思的,条理清晰容易理解。
但是觉得这样做挺繁琐的,除非能一眼看破需求,一击必中。
但我自认为目前还做不到这个水准,只能一步步的开发重构了。
o(╯□╰)o
四、基础功能代码。
对照着敲了敲井字棋的基础功能,有些语法做了一些改写。
明天有空再做一些优化和后面的提高难度吧。
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
//不含有stage的组件可以写成函数组件,避免class组件的繁琐。
// class Square extends React.Component {
// // constructor (props) {
// // super(props)
// // // this.state = {
// // // value: null,
// // // }
// // }
// clickButton () {
// // this.setState({
// // value: 'X',
// // })
// this.props.onClick()
// // console.log('触发了点击', this)
// // console.log('触发了点击', this.props)
// }
// render () {
// return (
// <button
// className='square'
// onClick={ _=>{this.clickButton()} }
// >
// {this.props.value }
// </button>
// )
// }
// }
const hasWinner = squares => {
const winnerMap = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
]
for(let i =0;i<winnerMap.length;i++) {
const [one,two,three] = winnerMap[i]
// 看图和squares的状态比较容易理解。
// 当one存在,并且等于two和three时,即为胜利。
// 因为one,two,three是取自胜利组合的数据。
if(squares[one] && squares[one] === squares[two] && squares[one] === squares[three]) {
return true
}
}
return false
}
function Square (props) {
return (
<button
className="square"
onClick={ props.onClick }
>
{props.value}
</button>
)
}
class Board extends React.Component {
// constructor (props) {
// super(props)
// this.state = {
// squares: Array(9).fill(null),
// nextStepIsO: true
// }
// }
// handleClick (i) {
// const squares = this.state.squares.slice()
// if(hasWinner(squares) || squares[i]) {
// return false
// }
// if(this.state.nextStepIsO) squares[i] = 'O'
// else squares[i] = 'X'
// this.setState({
// squares,
// nextStepIsO: !this.state.nextStepIsO
// })
// }
renderSquare (i) {
return (
<Square
value={ this.props.squares[i] }
onClick={ _ => this.props.onClick(i) }
/>
)
}
render () {
// const winner = hasWinner(this.state.squares)
// let status
// if(winner) {
// status = `winner! winner is:${this.state.nextStepIsO ? 'X':'O'}`
// } else {
// status = `Next player: ${this.state.nextStepIsO ? 'O':'X'}`
// }
return (
<div>
{/* <div className='status'>{ status }</div> */}
<div className='board-row'>
{ this.renderSquare(0) }
{ this.renderSquare(1) }
{ this.renderSquare(2) }
</div>
<div className='board-row'>
{ this.renderSquare(3) }
{ this.renderSquare(4) }
{ this.renderSquare(5) }
</div>
<div className='board-row'>
{ this.renderSquare(6) }
{ this.renderSquare(7) }
{ this.renderSquare(8) }
</div>
</div>
)
}
}
class Game extends React.Component {
constructor(props) {
super(props)
this.state = {
history: [{
squares: Array(9).fill(null)
}],
nextStepIsO: true,
currentStepNumber: 0
}
}
jumpTo(stepIndex) {
this.setState({
currentStepNumber: stepIndex,
nextStepIsO: (stepIndex % 2) === 0,
});
}
handleClick (i) {
const history = this.state.history.slice(0, this.state.currentStepNumber + 1);
const current = history[history.length - 1];
const squares = current.squares.slice();
if(hasWinner(squares) || squares[i]) {
return false
}
if(this.state.nextStepIsO) squares[i] = 'O'
else squares[i] = 'X'
const newHistory = history.concat([{squares}])
this.setState({
history: newHistory,
currentStepNumber: history.length,
nextStepIsO: !this.state.nextStepIsO
})
}
render () {
const history = this.state.history;
const currentItem = history[this.state.currentStepNumber]
const winner = hasWinner(currentItem.squares)
let status
if(winner) {
status = `winner! winner is:${this.state.nextStepIsO ? 'X':'O'}`
} else {
status = `Next player: ${this.state.nextStepIsO ? 'O':'X'}`
}
const moveLiList = history.map((stepData, stepIndex) => {
const desc = stepIndex ? `回到第${stepIndex} 步`: '开始游戏~'
return (
<li key={stepIndex}>
<button onClick={ _=> this.jumpTo(stepIndex)}>
{desc}
</button>
</li>
)
})
return (
<div className='game'>
<div className='game-board'>
{/* <div className='status'>{ status }</div> */}
<Board squares={currentItem.squares} onClick={ i => this.handleClick(i)}/>
</div>
<div className='game-info'>
<div>{ status }</div>
<ol>{ moveLiList }</ol>
</div>
</div>
)
}
}
// ========================================
ReactDOM.render(<Game />, document.getElementById('root'))