react学习笔记-从井字棋开始(2)

前言

接着前面的空格子棋 加上其他功能变成真正的井字棋

数字显示添加

传值 prop 方式

修改 Board 类的renderSquare函数

class Board extends React.Component {
  renderSquare(i) {   
  return <Square value={i} />;  
  }
   }

value = {i} 就是传值方式

同样的修改 Square 的渲染函数 接收参数并且 显示出来

class Square extends React.Component {
  render() {
    return (
      <button className="square">        
      {this.props.value}
      </button>
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGOqHDAQ-1617353498608)(en-resource://database/2034:1)]

给组件添加交互功能

Square 组件中 render() 方法的返回值中的 button 标签修改为如下内容:

class Square extends React.Component {
  render() {
    return (      
    <button className="square" onClick={function() { alert('click'); }}>                       {this.props.value}      
    </button>
    );
  }}

使用箭头函数代替 onClick={() => alert('click')}

使用state记录状态

可以通过在 React 组件的构造函数中设置 this.state 来初始化 state。this.state 应该被视为一个组件的私有属性。我们在 this.state 中存储当前每个方格(Square)的值,并且在每次方格被点击的时候改变这个值。

添加构造函数 初始化state

constructor(props) {    
super(props);    
this.state = {  
value: null,   
 };  
}

现在,我们来修改一下 Square 组件的 render 方法,这样,每当方格被点击的时候,就可以显示当前 state 的值了:

1.在 标签中,把 this.props.value 替换为 this.state.value。
2.将 onClick={…} 事件监听函数替换为 onClick={() => this.setState({value: ‘X’})}。

为了更好的可读性,将 className 和 onClick 的 prop 分两行书写。

render() {
    return (
      <button
        className="square"
        onClick={() => this.setState({value: 'X'})}
      >
        {this.state.value}
      </button>
    );
  }

setState 就是设置state的值
其中value 就是参数名
this.state.value 就是取值

使用子布局存储状态

给子布局添加Board构造函数 参数

使用一个arry储存状态

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
    };
  }

添加读取数组值的函数 根据传入的游标取值数组

renderSquare(i) {
    return <Square value={this.state.squares[i]} />;
  }

接下来,我们要修改一下 Square 的点击事件监听函数。Board 组件当前维护了那些已经被填充了的方格。我们需要想办法让 Square 去更新 Board 的 state。由于 state 对于每个组件来说是私有的,因此我们不能直接通过 Square 来更新 Board 的 state。

相反,从 Board 组件向 Square 组件传递一个函数,当 Square 被点击的时候,这个函数就会被调用。接着,我们将 Board 组件的 renderSquare 方法改写为如下效果:

在修改这个函数 添加一个handleClick函数 就是为了将点击事件从board传递到Square。

也就是说点击Square的时候同时触发了Board的函数

handleClick 现在还没有定义

  renderSquare(i) {
    return (
      <Square
        value={this.state.squares[i]}
        onClick={() => this.handleClick(i)}
      />
    );
  }

参数函数接收

现在我们从 Board 组件向 Square 组件中传递两个 props 参数:value 和 onClick。onClick prop 是一个 Square 组件点击事件监听函数。接下来,我们需要修改 Square 的代码:

1.将 Square 组件的 render 方法中的 this.state.value 替换为 this.props.value 。

2.将 Square 组件的 render 方法中的 this.setState() 替换为 this.props.onClick() 。

删掉 Square 组件中的构造函数 constructor,因为该组件不需要再保存游戏的 state。
进行上述修改之后,代码会变成下面这样:

class Square extends React.Component {
  render() {
    return (
      <button
        className="square"
        onClick={() => this.props.onClick()}
      >
        {this.props.value}
      </button>
    );
  }
}

props就是用来取值的:

props.value 取值value值
prop.onClick 是一个 Square 组件点击事件监听函数 也就是将点击事件传递下去

看清楚了发送和接收的关系对应

value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
onClick={() => this.props.onClick()
{this.props.value}

handleClick函数定义

handleClick(i) {
    const squares = this.state.squares.slice();
    squares[i] = 'X';
    this.setState({squares: squares});
  }

整体流程解析

每一个 Square 被点击时,Board 提供的 onClick 函数就会触发。我们回顾一下这是怎么实现的:

  1. 向 DOM 内置元素 添加 onClick prop,让 React 开启对点击事件的监听。
    当 button 被点击时,React 会调用 Square 组件的 render() 方法中的 onClick 事件处理函数。
  2. 事件处理函数触发了传入其中的 this.props.onClick() 方法。这个方法是由 Board 传递给 Square 的。
  3. 由于 Board 把 onClick={() => this.handleClick(i)} 传递给了 Square,所以当 Square 中的事件处理函数触发时,其实就是触发的 Board 当中的 this.handleClick(i) 方法。
  4. 现在我们还尚未定义 handleClick() 方法,所以代码还不能正常工作。如果此时点击 Square,你会在屏幕上看到红色的错误提示,提示内容为:“this.handleClick is not a function”。

简单说明就是:

点击Square这个事件会放到Board的renderSquare函数里面去处理

而renderSquare函数的点击事件就是handleClick函数 也就是处理点击事件的意思

handleClick函数则将参数Board state里的参数

arrayObject.slice(start,end) 返回值 返回一个新的数组

并设置点击的数组位置的变量为X,同时将新的数组返回给Board的state

因为点击事件改变了数组的值,同时传递Square的值也是数组的值。

这就等同于点击Square的时候改变了Square的值。

但是其实是在父布局完成了所有操作,只是交出来了点击权限。

React 术语中,我们把目前的 Square 组件称做“受控组件”。
在这种情况下,Board 组件完全控制了 Square 组件。

使用arrayObject.slice创建副本

在上一节内容当中,我们通过使用 .slice() 方法创建了数组的一个副本,而不是直接修改现有的数组。接下来我们来学习不可变性以及不可变性的重要性。

一般来说,有两种改变数据的方式。

第一种方式是直接修改变量的值,第二种方式是使用新的一份数据替换旧数据。

使用arrayObject.slice创建副本 修改之后替换原来的list。

而不是之间修改之前的list

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值