1 什么是JSX语法?

原生JS中,要向页面中挂载html标签,标签一定是被引号''包起来的:document.getElementById('root').append('<div>hello world</div>');

但在JSX语法中,不需要用引号包起来,这是JSX语法中的显著特点。

JSX中有两种类型的标签:

1⃣️普通的html标签(如App.js中的<div>hello</div>)

一般标签的首字母是小写的

2⃣️组件标签(如index.js中的<App />)

标签的首字母必须是大写的

2 React中的数据驱动思想和事件绑定

数据驱动思想:

React的所有功能都不直接操作DOM,而是直接操作数据。

在我们的TodoList项目中一共有两种数据:input中输入的数据页面上显示的数据,找到了它们就可以把网页完整渲染出来了。

事件绑定:

原生JS中为input绑定事件,使用的是onchange属性;

在React中要写成onChange,接着为其绑定一个函数,并在render函数上方定义这个函数。

<input value = {this.state.inputValue} onChange = {this.handleInputChange.bind(this)}/>

3 使用React编写TodoList

1)创建入口文件index.js,创建组件文件TodoList.js,在index.js中引入TodoList组件。

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList'; ReactDOM.render(<TodoList />, document.getElementById('root'));

2) 完善TodoList组件

1⃣️简单布局

render()函数只能识别一个标签,如果页面中有多个平级标签,要把它们最终包到一个div中,使得最外层只有一个标签。

但是在一些复杂的逻辑中,要求多个平级标签必须直接暴露在id为root的div中,不允许在外层再包裹一个div,那该怎么办呢?

React 16中提供了一个新的占位符组件Fragment,我们可以在TodoList组件中引入它,把多个标签统一放到Fragment标签中,就可以解决报错问题,且不会在页面中添加多余的标签。

//TodoList.js
import React , { Component , Fragment } from 'react'; class TodoList extends Component {
render() {
return (
<Fragment>
<input />
<ul>
<li>learn React</li>
<li>learn React</li>
</ul>
</Fragment>
);
}
} export default TodoList;

2⃣️在组件中定义项目中的数据

在我们的TodoList项目中一共有两种数据:input中输入的数据页面上显示的数据,找到了它们就可以把网页完整渲染出来了。

在render函数上方定义一个新的函数——constructor()函数

在组件被使用的一瞬间,会首先自动执行constructor函数,组件会接收外部传入的参数,并使用super函数把参数传递给其基类(基类就是父类,派生类就是子类)的构造函数中,在super后我们可以通过this.state来定义数据!【这里涉及到React的底层原理】

定义完数据后,我们需要在页面标签中引用这个数据,但是不能直接使用<input value = this.state.inputValue/>这种写法,因为这里使用的是JSX语法,如果直接将属性值 = 一个JS中的变量或者表达式,会报错,因此要将变量或表达式用花括号{}括起来——<input value = {this.state.inputValue}/>。

但是这里的数据是静态的,我们在输入框输入新的内容或想对其进行修改时会发现并不奏效,为了使数据能够动态的变化,我们需要为input绑定一个事件。

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

class TodoList extends Component {
constructor(props) {
super(props);
this.state = {
inputValue:'hello world',
list:[]
}
}
render() {
return (
<Fragment>
<input value = {this.state.inputValue}/>
<ul>
<li>learn React</li>
<li>learn React</li>
</ul>
</Fragment>
);
}
} export default TodoList;

3⃣️事件绑定

原来的this是undefined,input中数据变化,调用this.state时会报错,这里用es6中的bind方法,使this变为当前组件。然鹅,input中的值还是没有同步变化。。。

这是因为我们不能直接通过this.state来修改数据,而是要通过一个函数——this.setState()函数

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

class TodoList extends Component {
constructor(props) {
super(props);
this.state = {
inputValue:'hello world',
list:[]
}
}
handleInputChange(e) {
this.setState({
inputValue: e.target.value
});
}
render() {
return (
<Fragment>
<input value = {this.state.inputValue}
onChange = {this.handleInputChange.bind(this)}/>
<ul>
<li>learn React</li>
<li>learn React</li>
</ul>
</Fragment>
);
}
} export default TodoList;

4⃣️处理list中的数据

根据list中的数据的情况,将数据循环显示到页面中;使用es6中的map函数实现数组循环。

list中数据的显示:

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

class TodoList extends Component {
constructor(props) {
super(props);
this.state = {
inputValue:' ',
list:['learn React','learn Vue','learn JS']
}
}
handleInputChange(e) {
this.setState({
inputValue: e.target.value
});
}
render() {
return (
<Fragment>
<input value = {this.state.inputValue}
onChange = {this.handleInputChange.bind(this)}/>
<ul>
{
this.state.list.map((value,index) => {
return <li>{value}</li>
})
}
</ul>
</Fragment>
);
}
} export default TodoList;  

此时,数据能够成功显示,但控制台会报出警告⚠️index.js:1 Warning: Each child in a list should have a unique "key" prop.

为了使list中每个值能够唯一对应,我们需要为每条数据定义key属性

<li key = {index}>{value}</li>

动态显示list中数据:

实现在input输入数据后,敲回车,数据同步添加到list中。

我们要再为input绑定一个事件——onKeyUp

        handleKeyUp(e) {
if(e.keyCode === 13){
// const list = [...this.state.list];
//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
const list = [...this.state.list,this.state.inputValue];
this.setState({
list:list
});
}
}
render() {
return (
<Fragment>
<input value = {this.state.inputValue}
onChange = {this.handleInputChange.bind(this)}
onKeyUp = {this.handleKeyUp.bind(this)}/>
<ul>
{
this.state.list.map((value,index) => {
return <li key = {index}>{value}</li>
})
}
</ul>
</Fragment>
);
}
}   

进一步完善代码,对代码进行精简⬇️:

将初始list值置为空数组;

key和对应值相同不用重复写{list:list},直接写{list}即可。

实现按回车后,清空input中内容的功能。

	handleKeyUp(e) {
if(e.keyCode === 13){
// const list = [...this.state.list];
//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
const list = [...this.state.list,this.state.inputValue];
this.setState({
list,
inputValue:''
});
}
}

删除list中的数据:

实现点击某个列表项,就将其删除的功能。

需要为li标签绑定点击事件。

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

class TodoList extends Component {
constructor(props) {
super(props);
this.state = {
inputValue:' ',
list:[]
}
}
handleInputChange(e) {
this.setState({
inputValue: e.target.value
});
}
handleKeyUp(e) {
if(e.keyCode === 13){
// const list = [...this.state.list];
//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
const list = [...this.state.list,this.state.inputValue];
this.setState({
list,
inputValue:''
});
}
}
handleItemClick(index) {
const list = [...this.state.list];
list.splice(index,1);
this.setState({list});
}
render() {
return (
<Fragment>
<input value = {this.state.inputValue}
onChange = {this.handleInputChange.bind(this)}
onKeyUp = {this.handleKeyUp.bind(this)}/>
<ul>
{
this.state.list.map((value,index) => {
return <li key = {index}
onClick = {this.handleItemClick.bind(this,index)}
>
{value}
</li>
})
}
</ul>
</Fragment>
);
}
} export default TodoList;

4 更多JSX语法细节

1⃣️为标签绑定事件时,每次都要使用bind函数生成一个新函数来更新this,这样会对性能有影响。

我们可以把对this的绑定放到constructor函数中来做,这样只在组件创建一瞬间执行这段代码,不会每次触发都要执行一遍,提高了性能。

但如果bind函数中除了传递this还要传递其他参数,就不能使用这种方法了,因为这里每触发一次事件,传递但参数可能都是不同的,不能统一写到constructor中。

2⃣️循环获取list中的内容这部分也可以单独放到一个函数中。

3⃣️引入css样式

在src目录下创建css文件:style.css

在index.js中使用import引入css文件

import './style.css';

注:React会混淆定义组件的class关键字和标签中的class属性,因此要用className来定义标签中的class,否则控制台会有警告⚠️。

4⃣️for

实现点击输入框对应的label,输入框自动对焦。

<label for = 'myinput'>请输入内容:</label>
<input id = 'myinput'>

可以实现效果,但是这时控制台会报警告⚠️index.js:1 Warning: Invalid DOM property `for`. Did you mean `htmlFor`?

这是因为在JSX语法中,label中的for属性会与JS中的for循环关键字混淆,因此要把label中的for属性写为htmlFor

5⃣️JSX语法中的注释

JSX语法的标签中,无论是JS中的变量、表达式还是注释,都要用花括号{}包起来。

6⃣️实现当输入内容为空时,不添加到页面

增加一个判断条件

e.target.value !== ''

7⃣️html转义问题

在输入框中输入html标签,显示到页面中时会被转义为普通文本,如果想显示标签的效果要使用dangerouslySetInnerHTML = {{__html:value}}

dangerouslySetInnerHTML里面传的是一个JS对象

最终代码:

import React , { Component , Fragment } from 'react';
import './style.css' class TodoList extends Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.state = {
inputValue:'',
list:[]
}
}
handleInputChange(e) {
this.setState({
inputValue: e.target.value
});
}
handleKeyUp(e) {
if(e.keyCode === 13 && e.target.value !== ''){
// const list = [...this.state.list];
//es6中语法,相当于const list = ['learn React','learn Vue','learn JS']
const list = [...this.state.list,this.state.inputValue];
this.setState({
list,
inputValue:''
});
}
}
handleItemClick(index) {
const list = [...this.state.list];
list.splice(index,1);
this.setState({list});
}
getListItems() {
return this.state.list.map((value,index) => {
return <li key = {index}
onClick = {this.handleItemClick.bind(this,index)}
dangerouslySetInnerHTML = {{__html:value}}
>
</li>
})
}
render() {
return (
<Fragment>
<label htmlFor = 'myinput'>请输入内容:</label>
<input id = 'myinput'
className = 'input'
value = {this.state.inputValue}
onChange = {this.handleInputChange}
onKeyUp = {this.handleKeyUp}/>
<ul>
{ this.getListItems() }
</ul>
</Fragment>
);
}
} export default TodoList;

  

React笔记03——React实现TodoList的更多相关文章

  1. React笔记:React基础(2)

    1. JSX JSX是一种拥有描述UI的JavaScript扩展语法,React使用这种语法描述组件的UI. 1.1 基本语法 JSX可以嵌套多个HTML标签,可以使用大部分符号HTML规范的属性. ...

  2. React笔记01——React开发环境准备

    1 React简介 2013年由Facebook推出,代码开源,函数式编程.目前使用人数最多的前端框架.健全的文档与完善的社区. 官网:reactjs.org 阅读文档:官网中的Docs React ...

  3. React笔记02——React中的组件

    一个网页可以被拆分成若干小部分,每个部分都可以称为组件,即组件是网页中的一部分.组件中还可以有多个组件. 上一节中的App.js就是一个组件(继承了React.Component类的类). 一个组件的 ...

  4. React笔记_(3)_react语法2

    React笔记_(3)_react语法2 state和refs props就是在render渲染时,向组件内传递的变量,这个传递是单向的,只能继承下来读取. 如何进行双向传递呢? state (状态机 ...

  5. React笔记:组件(3)

    1. 组件定义 组件是React的核心概念,组件将应用的UI拆分成独立的.可复用的模块. 定义组件的两种方式: (1)类组件:使用ES6 class (2)函数组件:使用函数 使用class定义组件的 ...

  6. react笔记汇总

    1.什么是React? a.React 是一个用于构建用户界面的 JAVASCRIPT 库. b.React主要用于构建UI,很多人认为 React 是 MVC 中的 V. c.React 起源于 F ...

  7. React笔记

    React JS Tutorials for Beginners - 1 - Getting Started https://www.youtube.com/watch?v=-AbaV3nrw6E&a ...

  8. 14. react 基础 redux 的编写 TodoList 功能

    1. 安装 redux 监听工具 ( 需要翻墙 ) 打开 谷歌商店 搜索 redux devtool 安装第一个即可 2. 安装 redux yarn add redux 3. 创建 一个 store ...

  9. Node.js建站笔记-使用react和react-router取代Backbone

    斟酌之后,决定在<嗨猫>项目中引入react,整体项目偏重spa模式,舍弃部分server端的模板渲染,将一部分渲染工作交给前端react实现. react拥有丰富的组件,虽然不如Back ...

随机推荐

  1. JavaSE---多线程---集合类

    1.概述 1.1 Java提供的ArrayList.LinkedList.HashMap等都是线程不安全的类,如何解决: 1.1 使用Collections类提供的方法将  其  包装成线程安全类: ...

  2. mysql中limit 和 limit 与 offset 的用法(效果相同,用法不通过)

    例1,假设数据库表student存在13条数据. 代码示例: 语句1:select * from student limit 9,4 语句2:slect * from student limit 4 ...

  3. 【leetcode】946. Validate Stack Sequences

    题目如下: Given two sequences pushed and popped with distinct values, return true if and only if this co ...

  4. MariaDB 选择查询

    在本章中,我们将学习如何从表中选择数据. SELECT语句检索所选行. 它们可以包括UNION语句,排序子句,LIMIT子句,WHERE子句,GROUP BY ... HAVING子句和子查询. 查看 ...

  5. while循环语句基础

    while循环语句基础 一while循环语句介绍 循环语句命令常用于重复执行一条指令或一组指令,直到条件不再满足时停止,   Shell脚本语言的循环语句常见的有while, until, for及s ...

  6. redis requires Ruby version >= 2.2.2.

    安装RVM 无法在服务器使用curl命令访问https域名,原因是nss版本有点旧了,yum -y update nss更新一下 yum -y update nss 新建rvm-installer.s ...

  7. Network基础(三):网线的制作、交换机基本命令模式、交换机命令行基本配置、交换机的密码设置

    一.网线的制作 目标: 在常见的计算机网络中,网线主要用来连接计算机与交换机(或宽带路由器).交换机与交换机.交换机与路由器,以及需要连网的其他各种设备.网线的制作与测试是作为网络管理员的一个入门技能 ...

  8. 四. jenkins部署springboot项目(1)--window环境

    前提:jenkins和springboot运行在同一台机器 springboot项目使用git和maven jenkins所需的插件如Maven,Git等这里就不再详述. 1.jenkins配置git ...

  9. 框架-.NET:ASP.NET Core

    ylbtech-框架-.NET:ASP.NET Core ASP.NET Core是一个免费且开放源代码的Web框架,以及由微软和社区开发的下一代ASP.NET.它是一个模块化框架,既可以Window ...

  10. Let’s Encrypt Wildcard 免费泛域名SSL证书获取安装

    2018 年 1 月Let’s Encrypt CA 宣布免费提供通配符证书(Wildcard certificate).通配符证书是一种可被多个子域使用的公钥证书.这意味着,单个证书可用于提供多台服 ...