React笔记03——React实现TodoList
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的更多相关文章
- React笔记:React基础(2)
1. JSX JSX是一种拥有描述UI的JavaScript扩展语法,React使用这种语法描述组件的UI. 1.1 基本语法 JSX可以嵌套多个HTML标签,可以使用大部分符号HTML规范的属性. ...
- React笔记01——React开发环境准备
1 React简介 2013年由Facebook推出,代码开源,函数式编程.目前使用人数最多的前端框架.健全的文档与完善的社区. 官网:reactjs.org 阅读文档:官网中的Docs React ...
- React笔记02——React中的组件
一个网页可以被拆分成若干小部分,每个部分都可以称为组件,即组件是网页中的一部分.组件中还可以有多个组件. 上一节中的App.js就是一个组件(继承了React.Component类的类). 一个组件的 ...
- React笔记_(3)_react语法2
React笔记_(3)_react语法2 state和refs props就是在render渲染时,向组件内传递的变量,这个传递是单向的,只能继承下来读取. 如何进行双向传递呢? state (状态机 ...
- React笔记:组件(3)
1. 组件定义 组件是React的核心概念,组件将应用的UI拆分成独立的.可复用的模块. 定义组件的两种方式: (1)类组件:使用ES6 class (2)函数组件:使用函数 使用class定义组件的 ...
- react笔记汇总
1.什么是React? a.React 是一个用于构建用户界面的 JAVASCRIPT 库. b.React主要用于构建UI,很多人认为 React 是 MVC 中的 V. c.React 起源于 F ...
- React笔记
React JS Tutorials for Beginners - 1 - Getting Started https://www.youtube.com/watch?v=-AbaV3nrw6E&a ...
- 14. react 基础 redux 的编写 TodoList 功能
1. 安装 redux 监听工具 ( 需要翻墙 ) 打开 谷歌商店 搜索 redux devtool 安装第一个即可 2. 安装 redux yarn add redux 3. 创建 一个 store ...
- Node.js建站笔记-使用react和react-router取代Backbone
斟酌之后,决定在<嗨猫>项目中引入react,整体项目偏重spa模式,舍弃部分server端的模板渲染,将一部分渲染工作交给前端react实现. react拥有丰富的组件,虽然不如Back ...
随机推荐
- PyTorch 计算机视觉的迁移学习教程代码详解 (TRANSFER LEARNING FOR COMPUTER VISION TUTORIAL )
PyTorch 原文: https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html 参考文章: https://www ...
- 【leetcode】921. Minimum Add to Make Parentheses Valid
题目如下: 解题思路:上周都在忙着参加CTF,没时间做题,今天来更新一下博客吧.括号问题在leetcode中出现了很多,本题的解题思路和以前的括号问题一样,使用栈.遍历Input,如果是'('直接入栈 ...
- demo_service
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit ...
- One Switch for Mac 一键切换系统各项功能
One Switch 是火球工作室推出的最新 Mac效率软件,它在 Menubar 菜单里集成了隐藏桌面(图标).切换 Dark Mode.保持亮屏.开启屏保的一键切换按钮,将以往这些以独立小 ...
- Android学习--写一个发送短信的apk,注意布局文件的处理过程!!!
刚开始写Android程序如图发现使用了findViewById方法之后输出的话居然是null(空指针错误),也就是说这个方法没有成功.网上说这样写是在activity_main .xml去找这个ID ...
- GIT上传下载报错:[You do not have permission to pull from the repository]的解决方案!
第一步:打开我的电脑 第二步:选择此电脑,右击弹出框点击属性进入控制面板 第三步:进入控制面板 第四步:搜索管理凭据 第五步:编点击右侧按钮,进行编辑用户名和密码的操作添加凭据 git:https:/ ...
- 【转载】OsmocomBB在kali的安装方法
转载自http://www.nigesb.com/gsm-hacker-abhout-sms-sniffer.html 首先的首先需要建立Arm代码的编译环境,没有编译环境,就无法对osmocombb ...
- activemq学习总结 (转)Java消息队列--ActiveMq 实战
转:https://www.cnblogs.com/jaycekon/p/6225058.html 感谢作者 ActiveMQ官网下载地址:http://activemq.apache.org/dow ...
- 一起探讨下POST、GET请求
以下的讨论都是基于java和Spring MVC,主要记录自己的一些练习心得. 做web网站开发HTTP请求必不可少,一直在使用写好的Utils没有考虑过如何以及为什么,现在闲下来想着捋一捋java的 ...
- webpack构建缓存机制-hash介绍
前言 浏览器为了优化体验,会有缓存机制.如果浏览器判断当前资源没有更新,就不会去服务端下载,而是直接使用本地资源.在webpack的构建中,我们通常使用给文件添加后缀值来改名以及提取公共代码到不会改变 ...