• react入门小demo


    react入门小demo(TS版本)

    基于官方的入门demo进行TS改造

    准备

    初始化脚手架

    // 执行以下命令就能看到在当前目录my-app文件夹
    npx create-react-app my-app --template typescript
    

    找到my-app文件夹

    // 启动脚手架
    yarn start
    

    初始化demo

    • 将以下代码复制到app.css中
    body {
      font: 14px "Century Gothic", Futura, sans-serif;
      margin: 20px;
    }
    
    ol, ul {
      padding-left: 30px;
    }
    
    .board-row:after {
      clear: both;
      content: "";
      display: table;
    }
    
    .status {
      margin-bottom: 10px;
    }
    
    .square {
      background: #fff;
      border: 1px solid #999;
      float: left;
      font-size: 24px;
      font-weight: bold;
      line-height: 34px;
      height: 34px;
      margin-right: -1px;
      margin-top: -1px;
      padding: 0;
      text-align: center;
       34px;
    }
    
    .square:focus {
      outline: none;
    }
    
    .kbd-navigation .square:focus {
      background: #ddd;
    }
    
    .game {
      display: flex;
      flex-direction: row;
    }
    
    .game-info {
      margin-left: 20px;
    }
    
    
    • 将js复制到app.ts中
    class Square extends React.Component {
      render() {
        return (
          <button className="square">
            {/* TODO */}
          </button>
        );
      }
    }
    
    class Board extends React.Component {
      renderSquare(i) {
        return <Square />;
      }
    
      render() {
        const status = 'Next player: 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 {
      render() {
        return (
          <div className="game">
            <div className="game-board">
              <Board />
            </div>
            <div className="game-info">
              <div>{/* status */}</div>
              <ol>{/* TODO */}</ol>
            </div>
          </div>
        );
      }
    }
    
    
    export default Game;
    

    为Props添加类型声明

    1sKKAK.png

    我们迎来了类型系统的第一顿毒打,系统告诉我们这一行,没有匹配类型

    (props: Readonly<{}>): Square
    
    (props: {}, context?: any): Square
    
    <Square value={i}/> 
    

    这里一行与上述的类型声明不匹配,虽然我也看了TS一天,但是没发现上面的语法,官方也没看到和TS结合的例子,这个时候把错误信息复制到百度上去,解决方案就有了

    1sMDIK.png

    只需要这样

    class Square extends React.Component<any>
    

    解决了这个问题,我就发现,原来是因为我们Square组件的props类型没声明导致的,而reactReact.Component这种语法就可以声明我们的props类型,那么我们不要使用any,any只在特殊情况下使用,否则类型系统就失去意义了,这里我们使用接口描述props类型

    // 使用接口描述对象的类型
    interface SquareProps {
      value: number
    }
    // 这里使用此接口
    class Square extends React.Component<SquareProps> {
      render() {
        return (
          <button className="square">
            { this.props.value }
          </button>
        );
      }
    }
    

    1sltBR.png

    我们的代码正常运行了,继续按照官网实例完善代码

    给组件添加交互功能

    1s1e2D.png

    按照官方例子做,没有出现什么问题

    存储点击状态

    我们需要存储单元格的点击状态,需要使用state,就像以下代码

    class Square extends React.Component {
      constructor(props) {
        // 这里必须的
        super(props);
        // 初始化state
        this.state = {
          value: null,
        };
      }
    
      render() {
        return (
          <button className="square" onClick={() => alert('click')}>
            {this.props.value}
          </button>
        );
      }
    }
    

    使用state状态

    class Square extends React.Component {
      constructor(props) {
        // 这里必须的
        super(props);
        // 初始化state
        this.state = {
          value: null,
        };
      }
    
      render() {
        return (
          <button className="square" onClick={() => this.setState({value: 'X'})}>
            {this.state.value}
          </button>
        );
      }
    }
    

    constructor props类型

    新的类型错误出现了,props是一个隐式any类型,我们需要给它一个类型

    1s3Wp8.png

    class Square extends React.Component<SquareProps> {
      // 这里加上props类型
      constructor(props: SquareProps) {
        super(props)
        this.state = {
          value: null
        }
      }
      render() {
        return (
          <button className="square" onClick={() => this.setState({value: 'X'})}>
            { this.state.value }
          </button>
        );
      }
    }
    

    state类型

    1s88gS.png

    state中没有value,显而易见的是,我们需要为state声明类型,就想这样

    interface SquareProps {
      value: number
    }
    
    interface SquareState {
      value: string | null
    }
    
    class Square extends React.Component<SquareProps,SquareState> {
      constructor(props: SquareProps) {
        super(props)
        this.state = {
          value: null
        }
      }
      render() {
        return (
          <button className="square" onClick={() => this.setState({value: 'X'})}>
            { this.state.value }
          </button>
        );
      }
    }
    

    提取函数到类,设置函数类型

    class Square extends React.Component<SquareProps,SquareState> {
      constructor(props: SquareProps) {
        super(props)
        this.state = {
          value: null
        }
      }
      clickHandler = (e): void => {
        this.setState({value: 'X'})
      }
      render() {
        return (
          <button className="square" onClick={(e) => this.clickHandler(e)}>
            { this.state.value }
          </button>
        );
      }
    }
    

    1sBkOx.png

    event缺少类型,这里注意react的事件是合成事件不是原始事件

    // error
    clickHandler = (e: MouseEvent): void => {
      this.setState({value: 'X'})
    }
    // correct
    clickHandler = (e: React.MouseEvent): void => {
      this.setState({value: 'X'})
    }
    

    将状态提升到Board

    这一步需要将状态提升至Board组件

    interface BoardProps {
    
    }
    
    interface BoardState {
      squares: string []
    }
    
    class Board extends React.Component<BoardProps, BoardState> {
      // 编写constructor并且初始化state
      constructor(props: BoardProps) {
        super(props)
        this.state = {
          squares: Array(9).fill(null),
        }
      }
    
      handlerClick= (i: number) =>{
        const squares = this.state.squares.slice();
        squares[i] = 'X';
        this.setState({squares});
      }
    
      renderSquare(i: number) {
        // 传递onClick事件给子组件
        return <Square value={this.state.squares[i] } onClick={() => this.handlerClick(i)}/>;
      }
    
      render() {
        const status = 'Next player: 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>
        );
      }
    }
    

    删除Square组件状态

    Square组件的状态已经被提升到了Board组件,我们需要删除对应的状态

    interface SquareProps {
      value: string
      onClick: () => void
    }
    
    // SquareState也可以删除
    interface SquareState {
      value: string | null
    }
    
    class Square extends React.Component<SquareProps> {
      // 删除constructor
      // constructor(props: SquareProps) {
      //   super(props)
      //   this.state = {
      //     value: null
      //   }
      // }
    
    
      // clickHandler也可以删除
      // clickHandler = (e: React.MouseEvent): void => {
      //   this.setState({value: 'X'})
      // }
      render() {
        return (
          <button className="square" onClick={(e) => this.props.onClick()}>
            { this.props.value }
          </button>
        );
      }
    }
    

    改造Square组件为函数组件

    // 由于 无状态,所以改造成函数组件
    function Square(props: SquareProps) {
      return (
        <button className="square" onClick={props.onClick}>
          {props.value}
        </button>
      );
    }
    

    总结

    作为一个前端,Typescript主要被用在视图层,Vue2和TS结合不太友好,特别是在this的处理上,React与TS结合体验很好,适合用来学习TS,同时简单了解一下react,开拓一下思路。

  • 相关阅读:
    [Redis-CentOS7]Redis设置连接密码(九)
    [Redis-CentOS7]Redis数据持久化(八)
    PAT Advanced 1101 Quick Sort (25分)
    PAT Advanced 1043 Is It a Binary Search Tree (25分)
    HTTP协议
    PAT Advanced 1031 Hello World for U (20分)
    自然码双拼快速记忆方案
    macOS 原生输入法设置自然码
    PAT Advanced 1086 Tree Traversals Again (25分)
    PAT Advanced 1050 String Subtraction (20分)
  • 原文地址:https://www.cnblogs.com/sefaultment/p/12266441.html
Copyright © 2020-2023  润新知