react学习记录(二)井字棋基础功能开发和学习总结

入门教程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'))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值