React基础

1 使用Reat编写Todolist功能

TodoList.js
import React, { Component, Fragment } from 'react';
import './style.css';

class TodoList extends Component {
  //ECM6 继承语法
  //继承props方法
  constructor(props) {
    super (props);
    this.state = {
      inputValue: '',
      list: []
    }
  }
//input 中的内容存储在 inputValue中
//JSX语法
  render() {
      return (
      <Fragment>
        <div>
          {/* 这是一个注释 */}
          <label htmlFor="insertArea">输入内容:</label>
          <input
            id="insertArea"
            className='input'   //使用class
            value={this.state.inputValue}
            onChange={this.handleInputChange.bind(this)}  //在这里加this
          /> 
          <button onClick={this.handleBtnClick.bind(this)}>提交</button>
        </div>
        <ul>
          {
            this.state.list.map((item, index) => {
              return <li 
                      key={ index } 
                      onClick={this.hanleItemDelete.bind(this, index)}
                      //不转义显示
                      dangerouslySetInnerHTML = {{__html: item}}
                      >
												{ item }
                      </li>  // 用index做key值不好
            })
          }
        </ul>
      </Fragment>
    )
  }
  handleInputChange(e) {
    this.setState({
      inputValue: e.target.value
    })
    //console.log(this)
    //this.input.inputValue = e.target.value; //this指向不对哦
    //console.log(e.target.value);          //获得我们输入的内容
  }

  handleBtnClick() {
    this.setState({
      list: [...this.state.list, this.state.inputValue],
      //把原来数组的内容展开,再增加新的值
      inputValue: ''
    })
  }

  hanleItemDelete(index) {
    // immutable
    // state 不允许我们做任何改变
    //this.state.list.splice(index, 1);  --> 不能这样写

    const list = [...this.state.list]; //拷贝一份
    list.splice(index, 1);
    this.setState({
      list: list
    })
  }
}

export default TodoList;

2 React中的响应式设计思想和事件绑定

React中:不关注DOM只关注数据即可

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

class TodoList extends Component {
  //ECM6 继承语法
  //继承props方法
  constructor(props) {
    super (props);
    this.state = {
      inputValue: '',
      list: []
    }
  }
//input 中的内容存储在 inputValue中
//JSX语法
  render() {
      return (
      <Fragment>
        <div>
          <input 
            value={this.state.inputValue}
            onChange={this.handleInputChange.bind(this)}  //在这里加this
          /> 
          <button>提交</button>
        </div>
        <ul>
          <li>学英语</li>
          <li>learn English</li>
        </ul>
      </Fragment>
    )
  }
  handleInputChange(e) {
    this.setState({
      inputValue: e.target.value
    })
    //console.log(this)
    //this.input.inputValue = e.target.value; //this指向不对哦
    //console.log(e.target.value);            //获得我们输入的内容
  }
}

export default TodoList;

如上是我们编写的Todolist 的一段代码

我们需要注意的有:

1.在React中,编写在元素间的变量要使用{}。(JSX语法)

2.各个元素的状态,我们可以通过继承父类的方法props,然后使用this.state获取元素中的内容。

3.在使用对应的事件,进行一个事件绑定在调用函数的时候,我们要注意的是this的指向,因此我们通过ECM6的bind方法,预先改变该处理函数的一个this指向。

如上述代码中的:handleInputChange(this),我们需要的是组件的this, 来获得其中的值,并修改

4.我们不能通过this.input.inputValue来直接更改值,在React中给我们提供了方法:setState

如下:

this.setState({
      inputValue: e.target.value   //inputValue中的值和e.target.value中的值相等
  })

3 实现TodoList新增删除功能

以下是实现list一个增加和删除的代码

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

class TodoList extends Component {
  //ECM6 继承语法
  //继承props方法
  constructor(props) {
    super (props);
    this.state = {
      inputValue: '',
      list: []
    }
  }
//input 中的内容存储在 inputValue中
//JSX语法
  render() {
      return (
      <Fragment>
        <div>
          <input 
            value={this.state.inputValue}
            onChange={this.handleInputChange.bind(this)}  //在这里加this
          /> 
          <button onClick={this.handleBtnClick.bind(this)}>提交</button>
        </div>
        <ul>
          {
            this.state.list.map((item, index) => {
              return <li 
                      key={ index } 
                      onClick={this.hanleItemDelete.bind(this, index)}
                      >
                      { item }
                      </li>  // 用index做key值不好
            })
          }
        </ul>
      </Fragment>
    )
  }
  handleInputChange(e) {
    this.setState({
      inputValue: e.target.value
    })
    //console.log(this)
    //this.input.inputValue = e.target.value; //this指向不对哦
    //console.log(e.target.value);          //获得我们输入的内容
  }

  handleBtnClick() {
    this.setState({
      list: [...this.state.list, this.state.inputValue],
      //把原来数组的内容展开,再增加新的值
      inputValue: ''
    })
  }

  hanleItemDelete(index) {
    // immutable
    // state 不允许我们做任何改变
    //this.state.list.splice(index, 1);  --> 不能这样写

    const list = [...this.state.list]; //拷贝一份
    list.splice(index, 1);
    this.setState({
      list: list
    })
  }
}

export default TodoList;

3.1 新增li标签

我们要获得List中的值,并且显示在网页上,我们使用数组的map方法进行一个映射

ul标签中
<ul>
  {
    this.state.list.map((item, index) => {
      return <li 
              key={ index } 
              onClick={this.hanleItemDelete.bind(this, index)}
              >
              { item }
              </li>  // 用index做key值不好
    })
  }
</ul>
新增的事件函数
handleBtnClick() {
    this.setState({
    list: [...this.state.list, this.state.inputValue],
    //把原来数组的内容展开,再增加新的值
    inputValue: ''
   })
}

(1)新增li标签

如以上代码,我们使用数组的map方法来返回需要显示的内容。

需要注意的是,每个li必须含有一个关键字 key 并且必须是不同的,在这里我们使用了index,但是在React中,并不推荐使用Index,如果不使用的话,页面就会发出一个警告。

img

(2)添加按键事件方法

我们要改变的是List中的值,

我们同样使用了setState方法,

list: [...this.state.list, this.state.inputValue],

其中...this.state.list,获取原来的值,this.state.inputValue是获取输入框中的内容

之后,我们将输入框中的内容清除。

3.2 删除li标签

//ul标签中
<ul>
  {
    this.state.list.map((item, index) => {
      return <li 
              key={ index } 
              onClick={this.hanleItemDelete.bind(this, index)}
              >
              { item }
              </li>  // 用index做key值不好
    })
  }
</ul>
删除事件方法:
hanleItemDelete(index) {
  // immutable
  // state 不允许我们做任何改变
  //this.state.list.splice(index, 1);  --> 不能这样写

    //拷贝一份
  list.splice(index, 1);
  this.setState({
    list: list
  })
}

我们需要做的是:单击相应的内容,相应的内容就会删除。

  • 首先,我们获取对应的下标,通过bind方法来进行传参
  • 然后,我们创建一个新的list 拷贝 const list = […this.state.list]; 拷贝一份
  • 之后,通过数组的方法splice进行一个删除操作,
  • 最后,我们使用setState的方法来进行一个重新的赋值

【注】再次强调:state 不允许我们做任何改变,每次更改,必须使用setState方法

因此我们不能这样写 this.state.list.splice(index, 1);。这是错误的写法

在React中,我们将其称之为immutable规则。

4 拆分组件与组件之间传值

img

顶层组件:Todolist.js

其它都是子组件:TodoItem.js

我们将Todolist中组件进行一个分离,上面是按钮,下面是现实的li标签

img

当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。

Todolist.js
import React, { Component, Fragment } from 'react';
import './style.css';
import TodoItem from './TodoItem';

class TodoList extends Component {
  //ECM6 继承语法
  //继承props方法
  constructor(props) {
    super (props);
    this.state = {
      inputValue: '',
      list: []
    }
  }
//input 中的内容存储在 inputValue中
//JSX语法
  render() {
      return (
      <Fragment>
        <div>
          {/* 这是一个注释 */}
            <label htmlFor="insertArea">输入内容:</label>
            <input
                id="insertArea"
                className='input'   //使用class
                value={this.state.inputValue}
                onChange={this.handleInputChange.bind(this)}  //在这里加this
          /> 
          <button onClick={this.handleBtnClick.bind(this)}>提交</button>
        </div>
        <ul>
          {
            this.state.list.map((item, index) => {
              return (
                    <TodoItem 
                        content={item} 
                        index={index}
                        deleteItem = {this.hanleItemDelete.bind(this)} //传递方法
                        />
                    )
                    
            })
          }
        </ul>
      </Fragment>
    )
  }
  handleInputChange(e) {
    this.setState({
      inputValue: e.target.value
    })
    //console.log(this)
    //this.input.inputValue = e.target.value; //this指向不对哦
    //console.log(e.target.value);          //获得我们输入的内容
  }

  handleBtnClick() {
    this.setState({
      list: [...this.state.list, this.state.inputValue],
      //把原来数组的内容展开,再增加新的值
      inputValue: ''
    })
  }

  hanleItemDelete(index) {
    // immutable
    // state 不允许我们做任何改变
    //this.state.list.splice(index, 1);  --> 不能这样写

    const list = [...this.state.list]; //拷贝一份
    list.splice(index, 1);
    this.setState({
      list: list
    })
  }
}

export default TodoList;
TodoItem.js
import React,{Component}from 'react';

class TodoItem extends Component {

    constructor(props) {
        super (props);
        //使用这种写法,节约性能
        this.handleClick = this.handleClick.bind(this);
    }

    render() {
        return <li key={1} onClick={this.handleClick}>{this.props.content}</li>
    }
    //子组件调用父组件的方法来修改内容
    handleClick(){
        this.props.deleteItem(this.props.index);
    }
}

export default TodoItem;

4.1 父组件传值给子组件并使用

(1)父组件传值给子组件

以上是所有的代码,主要发生改变的是如下代码:

<ul>
  	{
      this.state.list.map((item, index) => {
        return (
          <TodoItem 
          content={item} 
          index={index}
      		deleteItem = {this.hanleItemDelete.bind(this)} //传递方法
      		/>
      	)
			})
    }
</ul>

在父节点中我们通过 <TodoItem />来调用子组件

我们父节点传值,类似属性的方式 变量名 = {传值} 来给子组件传值,然后子组件就可以进行调用了。

(2)子组件使用父组件的值

TodoItem.js
import React,{Component}from 'react';

class TodoItem extends Component {

    constructor(props) {
        super (props);
        //使用这种写法,节约性能
        this.handleClick = this.handleClick.bind(this);
    }

    render() {
        return <li key={1} onClick={this.handleClick}>{this.props.content}</li>
    }
    //子组件调用父组件的方法来修改内容
    handleClick(){
        this.props.deleteItem(this.props.index);
    }
}

export default TodoItem;

我们使用父组件传值给我们,我们通过 this.props.变量名的方法来调用父组件的值。

4.2 子组件调用父组件的方法

(1)父组件传递方法给子组件

父组件传给子组件的方法类似于传值,但是在这里我们需要的是,这个方法的this必须指向的是父组件。因为父组件可以调用该方法,而子组件中没有该函数。

如果没有强制改变this的指向,那么在网页上报错,没有发现该函数,即无法调用。

deleteItem = {this.hanleItemDelete.bind(this)} //传递方法

(2)子组件调用父组件的方法

子组件在进行事件的时候,也要改变this的指向,我们通过如下的方法,比直接使用bind的方法更节约性能。

constructor(props) {
  super (props);
  //使用这种写法,节约性能
  this.handleClick = this.handleClick.bind(this);
}

在调用父节点的方法的时候,我们同样通过,this.props.方法进行调用

handleClick(){
  	this.props.deleteItem(this.props.index);
}

5 TodoList代码优化

优化主要使用了一些ECM6的语法:

1.大括号解构

const {content} = this.props;

2.箭头函数

3.将强制改变this指向的,写到最前面constructor中,提升效率,之后使用也方便

如: this.handleInputChange = this.handleInputChange.bind(this);

4.将setState中返回函数,而不是对象,异步操作,提升效率

5.使用prevState来表示之前的变量

6.如果在标签中,使用的代码过多,使用函数进行封装。

7.ul标签中的循环,要增加key值,要增加在最外层的元素上,不推荐使用index。

5.1 TodoItem.js

import React,{Component}from 'react';

class TodoItem extends Component {

    constructor(props) {
        super (props);
        //使用这种写法,节约性能
        this.handleClick = this.handleClick.bind(this);
    }

    render() {
        const {content} = this.props;
        //相当于 const content = this.props.conetent;
        return (
            <li  onClick={this.handleClick}>
                {content}
            </li>
        )
    }
    //子组件调用父组件的方法来修改内容
    handleClick(){
        const {deleteItem, index} = this.props;
        deleteItem(index);
    }
}

export default TodoItem;

5.2 TodoList.js

import React, { Component, Fragment } from 'react';
import TodoItem from './TodoItem';
import './style.css';

class TodoList extends Component {
    //ECM6 继承语法
    //继承props方法
    constructor(props) {
        super (props);
        this.state = {
        inputValue: '',
        list: []
        }
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleBtnClick = this.handleBtnClick.bind(this);
        this.hanleItemDelete = this.hanleItemDelete.bind(this);
    }

//input 中的内容存储在 inputValue中
//JSX语法
    render() {
        return (
        <Fragment>
            <div>
            {/* 这是一个注释 */}
                <label htmlFor="insertArea">输入内容:</label>
                <input
                    id="insertArea"
                    className='input'   //使用class
                    value={this.state.inputValue}
                    onChange={this.handleInputChange}  //在这里加this
                /> 
            <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}
                    deleteItem = {this.hanleItemDelete} //传递方法
                />
            )        
        })
    }

    //返回对象 ES6  异步,性能提升  对象变成函数 注意target
    handleInputChange(e) {
        const {value} = e.target;
        this.setState(() =>({
                inputValue: value  
            }))
        }
    /* 
    handleInputChange(e) {
        this.setState({
        inputValue: e.target.value
        })
    } 
    */

    //prevState接受之前的参数
    handleBtnClick() {
        this.setState((prevState) => ({
            list: [...prevState.list, prevState.inputValue],
            inputValue: ''
        }))
    }
    /* 
    handleBtnClick() {
    this.setState({
    list: [...this.state.list, this.state.inputValue],
    //把原来数组的内容展开,再增加新的值
    inputValue: ''
    })
    } */

    hanleItemDelete(index) {    
        this.setState((prevState) => {
            const list = [...prevState.list];
            list.splice(index, 1);
            return {list  /*等效于list:list*/}
        })
    }
    /* 
    hanleItemDelete(index) {  
        const list = [...this.state.list]; 
        list.splice(index, 1);
        this.setState({
          list: list
        })
    } 
    */
}
  
export default TodoList;

运行结果:没有问题!!!!!!!!

img

6 React的概念及思考

6.1 开发方式

命令式编程(先做什么,再做什么) -> DOM操作(Jquery, 原生JS)

声明式开发(react自动根据数据构造页面DOM,这个数据可以理解为图纸。) -> React(节约DOM操作代码)

6.2 可以与其它框架并存(Jquery)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div><span>abc</span></div>
  </body>
</html>

如在index.html中,React只对 <div id="root"></div>生效(因为这里react是挂载在root上的。对于下面的

abc
可以用其他框架,比如jQuery,前提是不能影响它之外的框架。)

其它操作依然可以生效。

img

6.3 组件化开发

首字母大写是组件(首字母小写是标签元素。)

父组件 -> 传值给 子组件

子组件 -> 传值给 父组件 调用父组件的方法(子组件使用父组件传给的方法来修改父组件传的值(不能直接使用未传的方法来修改父组件传的值))

6.4 单向数据流

父组件可以向子组件传递内容,但是子组件只可以使用,但不可以改变(否则会报错,只读不可更改)

为了让开发方便,因为如果多个组件都可以对其进行修改,那么不知道是那个发生改变。

如果要改->通过子组件调用父组件的方法

6.5 视图层的框架

如果是紫色的传值,会很麻烦

因此在开发项目,不仅仅用到React,传值交给其它组件完成,React负责数据和页面渲染

因此,使用flask,Redux来辅助开发(数据层框架负责传值)

imgimg

6.6 函数式编程

维护方便 (给需要测试函数一个参数,通过函数输出来判断函数是否运行正确。)

面向测试的开发流程->前端自动化测试->提高便捷性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值