likes
comments
collection
share

(09)React 入门——⑥ TodoList 代码优化 | React 基础理论实操

作者站长头像
站长
· 阅读数 22
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 TodoItem.js 代码优化

之前的几篇文章,我们完整地做出了 TodoList 的相关功能。但由于讲解的需要,其中有一些代码并不符合“标准 React 编码规范”。

本篇我们对之前的代码进行一些“优化”。

打开 TodoItem.js 文件,需要优化的点:

  • 为了“性能”,我们一般把与“this 指向绑定”相关的代码都统一放在 constructor 里边;
  • 能用 ES6 的地方,尽可能地用 ES6 语法(如本例中的“对象解构赋值”)。

🔗前置知识:《解构赋值:数组、对象、函数的解构赋值》

❎以下为原代码和“标记”的需要优化的地方:

import React, { Component } from "react";

class TodoItem extends Component {

  
  render() {
    return(
      <div onClick={this.handleClick.bind(this)}> {/*
      																						 ❎-①:我们一般把与“this 指向绑定”相关
      																						 的代码都统一放在 constructor 里边;
                                                    */}
        
		  	{this.props.content} {/* ❎-②:用 ES6 语法——对象的解构赋值; */}
      </div>
    )
  }
  
  handleClick() {  
    this.props.itemDelete(this.props.index) {/* ❎-③:同理,用 ES6 语法——对象的解构赋值。 */}
  }
}

export default TodoItem;

✔️以下为“优化”后的代码:

import React, { Component } from "react";

class TodoItem extends Component {
  constructor(props) {
    super(props);
    
    this.handleClick = this.handleClick.bind(this);
  } 
  
  render() {
    const {content} = this.props
    
    return(
      <div onClick={this.handleClick}> 
        {content}  
      </div>
    )
  }
  
  handleClick() {  
    const {itemDelete, index} = this.props
    
    itemDelete(index)
  }
}

export default TodoItem;

2 TodoList.js 代码优化

打开 TodoList.js 文件,需要优化的点:

  • 同理,为了“性能”,我们一般把与“this 指向绑定”相关的代码都统一放在 constructor 里边;

  • JSX 中,我们一般放置的是页面上会显示的内容。因此,我们尽可能地不要在里边放很多“逻辑代码”,与“逻辑”相关的代码,我们直接提取出来用一个“方法”来表示

  • 新版 React 中,已经不推荐诸如下面的写法(传入对象的形式)来修改“数据”项了:

this.setState({
  inputValue: e.target.value  
})

取而代之的是,采用“传入函数”的形式来修改“数据”项。

❗️❗️❗️但要注意,采用这种“函数”的形式传入时,它会变成一个“异步”的 setState(我们后边讲“虚拟 DOM”时,会详细讲解为什么需要一个“异步”的 setState),我们要“显式”的在外层对 value 值进行保存,然后再在内层去使用它。否则会报错!

const value = e.target.value
this.setState(() => ({
  inputValue: value
}))
  • setState 里边可以接受一个参数叫 prevState

    • prevState 指的是:修改数据之前时的 state 是什么样的。所以,在代码中,遇到“修改数据之前时的 state ”时(如 this.state.list ),我们可以直接改写成 prevState.list

    • 采用 prevState 的好处:它可以让我们避免由于不小心而去改动了 state 的状态。

  • 我们做“循环”时,要记得给“循环”的每一项添加一个“唯一”的 key 值。本例中,我们暂时用 index 作为这个“唯一”的值。但 index 作为 key 值,是一种不好的方式,它很有可能会造成代码的报错。具体怎么才是最好的方式,待我们后边讲“虚拟 DOM”时,再详细讲解。

❎以下为原代码和“标记”的需要优化的地方:

import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);

    this.state = {
      inputValue: "", 
      list: []
    };
  }

  render() {
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange.bind(this)} {/*
-①:我们一般
            																					把与this 指向绑定相关的代码
                                                      都统一放在 constructor 里边
                                                           */}
          />

          <button onClick={this.handleBtnClick.bind(this)}> {/*
          																					❎-②:我们一般
          																					把与“this 指向绑定”相关的代码
                                                    都统一放在 constructor 里边;
                                                              */}
            提交
          </button>
        </div>

        <ul>
          {/* ❎-④:JSX 里,与“逻辑”相关的代码,我们要尽可能地抽离成“方法”! */}
          {
            this.state.list.map((item, index)=>{ 
              return( 

                <TodoItem 
                  content={item}

                  index={index} 
                  itemDelete={this.handleItemDelete.bind(this)} {/*
-③:我们一般
                  																		 	把与this 指向绑定相关的代码
                                                       	都统一放在 constructor 里边
                                                        				  */}
                />  
              )  
            })
          }
        </ul>

      </Fragment>
    )
  }

  handleInputChange(e) {
    this.setState({ /*
    								❎-⑤:新版 React 提倡我们用“传入函数”的形式修改“数据项”;
    								用这种形式时,要注意先在外层对 value 值进行保存,然后才能在内层进行使用!
                     */
      inputValue: e.target.value  
    })
  }

  handleBtnClick() {
    this.setState({ /*
    								❎-⑥:新版 React 提倡我们用“传入函数”的形式
                    修改“数据项”;
                     */
      
      list: [...this.state.list, this.state.inputValue], /*
      																									 ❎-⑦:用 prevState 来代替
      																									 数据“修改前”的状态;
                                                          */
      inputValue: ""  
    }) 
  }

  handleItemDelete(index) { 
    const list = [...this.state.list] /*
    																	❎-⑨:用 prevState 来代替
      																数据“修改前”的状态;
                                       */
    
    list.splice(index, 1)  
    this.setState({ // ❎-⑧:新版 React 提倡我们用“传入函数”的形式修改“数据项”;
      list: list 
    }
    )
  }
}

export default TodoList;

✔️以下为“优化”后的代码:

import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: "", 
      list: []
    };
    
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
  }

  render() {
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange}
          />

          <button onClick={this.handleBtnClick}>
            提交
          </button>
        </div>

        <ul>
          {this.getTodoItem()}
        </ul>

      </Fragment>
    )
  }

  getTodoItem() {
    return this.state.list.map((item, index) => { 
      return( 
        <TodoItem 
          key={index}
        
          content={item}
          index={index} 
          itemDelete={this.handleItemDelete}
        />  
      )  
    })
  }
  
  handleInputChange(e) {
    const value = e.target.value
    
    this.setState(() => ({
      inputValue: value
    }))
  }

  handleBtnClick() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],  
      inputValue: ""        
    }))
  }

  handleItemDelete(index) { 
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
        
      return {list}
 
    })
  }
}

export default TodoList;

最后看看页面效果(没“报错”、没“警告”):

(09)React 入门——⑥ TodoList 代码优化 | React 基础理论实操

祝好,qdywxs ♥ you!