传送门:
React教程(一):React基础

一.组件概念

react官方解释:
React 允许你将标记、CSS 和 JavaScript 组合成自定义“组件”,即应用程序中可复用的 UI 元素。

个人理解:
组件是对一些UI和数据的封装,便于复用和维护。

可以把页面中的所有组成部分都当成是组件,即可以把页面中一切元素都当成是组件(比如一个简单的button按钮)。组件可大可小,大的组件代码较多能够完成丰富的功能实现和展示,小的组件也许就是一个简单的标签而已。不同的组件有不同的功能,组件可以嵌套可以组合等等

理解了这些概念之后,就会发现其实所有的页面都可以由多个组件构成,比如导航组件、商品展示组件、购物车组件等等。

放一张图更好的理解组件:

二.函数组件

React组件分为函数组件类组件,我们先来了解一下函数组件。

1.概念

使用JS的函数(或者箭头函数)创建的组件,叫做函数组件

2.定义与渲染

// 引入react核心包
import React from "react";
其他的时间
// 普通函数形式定义函数组件
function MyComponent() {return <div>我是一个函数组件</div>;
}
// 箭头函数形式定义函数组件
const MyComponent2 = () => {return <div>我是一个函数组件</div>;
};
function App() {return (<div>{/* 使用时可以双标签闭合 */}<MyComponent></MyComponent>{/* 也可以单标签闭合 */}<MyComponent /><MyComponent2 /></div>);
}
// 导出组件
export default App;

3. 约定说明

  1. 组件的名称必须首字母大写,react内部会根据这个判断是组件还是HTML标签。
  2. 函数组件必须要有返回值,表示该组件的UI结构,如果不需要渲染任何内容则返回null。
  3. 组件就像HTMl标签一样可以被渲染到HTMl页面中,组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数的返回值对应的内容

三. 类组件

1. 概念

使用ES6的class创建的组件,叫做类组件。

2. 定义与渲染

// 引入react核心包
import React from "react";// 定义类组件
// 表示继承React组件类(父类)
class Hello extends React.Component {// render函数用于渲染uirender() {return <div>我是类组件</div>; /* 返回值 */}
}
function App() {return (<div><Hello /></div>);
}// 导出组件
export default App;

3.约定说明

  1. 类名也必须以大写字母开头
  2. 类组件应该是继承React.Component父类,从而使用父类中提供的方法或属性。
  3. 类组件必须提供render方法,render方法必须有返回值,表述组件的UI结构

四. 组件事件绑定

1. 如何绑定事件

  • 语法
    on + 事件名 = (事件处理函数),例如绑定一个点击事件:
<div onClick={()=>{}}>点我</div>
  • 注意点
    react 事件采用驼峰命名法,比如onClick、onMouseEnter、onFocus
  • 样例
// 引入react核心包
import React from "react";// 函数组件
const HelloWorld = () => {// 定义事件回调函数const dealClick = () => {alert("函数组件,你好");};return <div onClick={dealClick}>点我弹出你好</div>;
};
// 类组件
class Hello extends React.Component {// 定义事件回调函数(标准写法,避免this组件问题),回调函数中的this会指向当前的实例对象dealClick = () => {alert("类组件,你好");};render() {// this会指向当前的实例对象(表示调用实例对象中的方法)return <div onClick={this.dealClick}>点我弹出你好</div>; /* 返回值 */}
}
function App() {return (<div><HelloWorld /><Hello /></div>);
}export default App;
  • 注意点:
    在类组件中,请注意定义事件函数的标准写法,避免this指向问题:
  dealClick = () => {alert("类组件,你好");};

2. 获取事件对象

  • 通过事件处理程序的参数获取事件对象
// 引入react核心包
import React from "react";// 函数组件
const HelloWorld = () => {// 定义事件回调函数const dealClick = (e) => {// 阻止默认事件(此时a标签被点击则不会触发跳转事件)e.preventDefault();console.log("e事件对象", e);};return (<a onClick={dealClick} href="www.baidu.com">点我打印事件对象</a>);
};function App() {return (<div><HelloWorld /></div>);
}export default App;

可见事件对象e被打印到了控制台。

  • 事件绑定传递自定义参数

利用箭头函数的形式去传递额外参数

const HelloWorld = () => {// 定义事件回调函数const dealClick = (msg) => {console.log("msg", msg);};return (<divonClick={() => {dealClick("icy is godlike");}}>点我打印msg</div>);
};
function App() {return (<div><HelloWorld /></div>);
}export default App;

执行的结果:

  • 同时传递额外参数和获取事件对象e
    需要将事件对象e作为形参传递。
const HelloWorld = () => {// 定义事件回调函数const dealClick = (e, msg) => {// 此处接收时间对象e和额外参数msgconsole.log("e事件对象", e);console.log("msg", msg);};return (<divonClick={(e) => {// 需要在此处将事件对象e作为形参传入dealClick(e, "icy is godlike");}}>点我打印msg和事件对象e</div>);
};

打印的结果:

写法小结:

  1. 不需要传递参数 onClick={函数名} ,在该函数中可以直接获取事件对象e
  2. 需要传递参数 onClick = { ( )=>{ 函数名(参数) } } // 利用箭头函数
  3. 需要事件对象e又需要传递参数 ,把e作为参数传入
    onClick = { ( ) => { 函数名(e, 其他参数) } }

五. 组件状态

背景:

在react hook 出现之前,函数组件没有自己的状态,所以我们先通过类组件来讲解组件状态。

流程: 初始化状态 -> 读取状态-> 修改状态 -> 影响视图

1.初始化状态

  • 通过类的实例属性state来初始化状态
  • state的值是一个对象结构,表示一个组件可以有多个数据状态
class HelloWorld extends React.Component {state = {count: 81,};render() {return <div></div>;}
}

2.读取状态

通过this.state 来读取状态

class HelloWorld extends React.Component {state = {count: 81,name: "icy",};render() {return (<div>{this.state.name}的体重:{this.state.count}<div><button>点我减少体重</button></div></div>);}
}

渲染出来的效果:

3.修改状态

通过this.setState() 方法来修改
注意: 不可以直接赋值修改

class HelloWorld extends React.Component {// 初始化状态state = {weight: 81,name: "icy",};// 定义回调函数修改状态loseWeight = () => {this.setState({// 将state中的值解构出来...this.state,// 修改count的值为原来的值减1weight: this.state.weight - 1,});// 打印一下结果console.log("icy的体重:", this.state.weight);};render() {return (<div>{this.state.name}的体重:{this.state.weight}<div>{/* 这里别忘记了绑定事件 */}<button onClick={this.loseWeight}>点我减少体重</button></div></div>);}
}

执行的结果:

注意事项:

  1. 修改基本数据类型
this.setState({name:'新的值'})
  1. 修改复杂数据类型(对象,数组),可以通过扩展运算符解构(浅拷贝)
this.setState(list:[...this.state.lsit,'新的一项']

3.注意如果state中状态过多,也可以通过解构赋值来修改

   this.setState({// 将state中的值解构出来...this.state,// 修改count的值为原来的值减1weight: this.state.weight - 1,});

六. this指向问题说明

必须谨慎对待JSX回调函数中的this,在javascript中,class方法默认不会绑定this,如果忘记绑定 this.handleClick,并把它传入onClick,则当你调用这个函数的时候,this的值将会为undefined。

代码说明:

1.错误的使用方法

class HelloWorld extends React.Component {// 初始化状态state = {weight: 81,name: "icy",};// 定义回调函数修改状态loseWeight() {this.setState({// 将state中的值解构出来...this.state,// 修改count的值为原来的值减1weight: this.state.weight - 1,});// 打印一下结果console.log("icy的体重:", this.state.weight);}render() {return (<div>{this.state.name}的体重:{this.state.weight}<div><button onClick={this.loseWeight}>点我减少体重</button></div></div>);}
}

此时会报错,因为this为undefined。

2. 正确的写法(1)

在类的构造函数constructor中手动改变回调函数的this指向

class HelloWorld extends React.Component {// 初始化状态state = {weight: 81,name: "icy",};constructor() {// super()固定写法用来继承父类的方法或属性super();// 使用bind函数改变loseWeight的this指向为当前类的实例对象// 即在组件初始化时就修正了该方法的this指向this.loseWeight = this.loseWeight.bind(this);}// 定义回调函数修改状态loseWeight() {this.setState({// 将state中的值解构出来...this.state,// 修改count的值为原来的值减1weight: this.state.weight - 1,});// 打印一下结果console.log("icy的体重:", this.state.weight);}render() {return (<div>{this.state.name}的体重:{this.state.weight}<div><button onClick={this.loseWeight}>点我减少体重</button></div></div>);}
}
export default App;

3.正确的写法(2)

给onClick绑定事件时,使用箭头函数的写法

class HelloWorld extends React.Component {// 初始化状态state = {weight: 81,name: "icy",};// 定义回调函数修改状态loseWeight() {this.setState({// 将state中的值解构出来...this.state,// 修改count的值为原来的值减1weight: this.state.weight - 1,});// 打印一下结果console.log("icy的体重:", this.state.weight);}render() {return (<div>{this.state.name}的体重:{this.state.weight}<div><button/* 此处使用箭头函数写法,箭头函数没有自己的this,会向作用域链上级查找 */onClick={() => {this.loseWeight();}}>点我减少体重</button></div></div>);}
}

4.正确的写法(3)最推荐的写法

在定义回调函数时,直接使用箭头函数的写法。

class HelloWorld extends React.Component {// 初始化状态state = {weight: 81,name: "icy",};// 此处直接写成箭头函数的形式,从而引用作用域链上级的thisloseWeight = () => {this.setState({// 将state中的值解构出来...this.state,// 修改count的值为原来的值减1weight: this.state.weight - 1,});// 打印一下结果console.log("icy的体重:", this.state.weight);};render() {return (<div>{this.state.name}的体重:{this.state.weight}<div>{/* 此处保持原样 */}<button onClick={this.loseWeight}>点我减少体重</button></div></div>);}
}

七.React的状态不可变说明

**概念:**不要直接修改状态的值,而是基于当前状态创建新的状态值。

1.错误的做法:直接修改state的值

  // 初始化状态state = {weight: 81,list: [1, 2, 3],person: {name: "icy",age: 23,},};updateState = () => {// 直接修改简单类型Number(错误,千万别这么干,达咩)this.state.weight++;++this.state.weight;this.state.weight += 1;this.state.weight = 70;// 直接修改数组 千万别这么干,达咩!!this.state.list.push(2222);this.state.list.slice(1, 2);// 直接修改对象 千万别这么干,达咩达咩哟!!this.state.person.name = "icy大魔王";};

vscode也会给出warning,让你别这么干。

2.正确的做法:基于当前状态创建新的值

this.setState({count: this.state.count + 1,list: [...this.state.list, 4],person: {...this.state.person,// 解构然后覆盖原来的name,实际工作中中常用写法name: "icy大魔王",},});

八.处理表单

使用React处理表单元素,一般有两种方式:

1.受控组件(推荐使用)
2.非受控组件

1.受控表单组件

什么是受控组件?
受控组件是可以被react的状态控制的组件
React组件的状态在state中,input表单元素也有自己的状态在value中,React将state与表单元素的值(value)绑定到一起,由state的值来控制表单元素的值,从而保证单一数据源特性。

实现步骤:
以获取文本框的值为例,受控组件使用步骤如下:

  1. 在组件的state中声明一个组件的状态数据
  2. 将状态数据设置为input标签元素的value属性的值
  3. 为input添加onChange事件
  4. 在事件处理函数中,通过事件对象e获取到当前文本框的值(即用户输入的值)
  5. 调用setState方法,将文本框的值作为state状态的最新值。

代码演示:

class HelloWorld extends React.Component {// 初始化状态state = {// 用来控制input输入框的value状态,初始为空text: "",};// 事件处理函数changeText = (e) => {// 使用e事件对象获取用户输入的值,并打印出来看看对不对// 此处也可以自行打印e对象,看看value是如何拿到的console.log("用户输入的值:", e.target.value);// 使用setStae改变state的状态为用户输入的值this.setState({text: e.target.value,});};render() {return (<div>{/* 此处value绑定state中的text状态 同时绑定表单的onChange事件*/}<input value={this.state.text} onChange={this.changeText} /></div>);}
}

控制台效果:

如果大家还学过vue,vue中有个v-model指令可以双向绑定表单数据,以上也是双向绑定的原理。

2.非受控组件

什么是非受控组件?
非受控组件是通过手动操作dom的方式获取文本框的值,文本框的状态不受react组件中的state控制,直接通过原生dom获取输入框的值。

实现步骤:

  1. 导入createRef函数
  2. 调用createRef函数,创建一个ref对象,存储到名为xxxx(自定义名字如如:msgRef)的实例属性中
  3. 为input添加属性,值为msgRef(上面自定义的名字)
  4. 在按钮的事件处理函数中,通过msgRef.current(固定写法)即可拿到input对应的dom元素,而其中msgRef.current.value(固定写法)拿到的则是文本框的值。

代码演示:

class HelloWorld extends React.Component {// 使用createRef创建一个可以存放dom对象的容器msgRef = createRef();changeMsg = () => {// 获取输入框用户输入的值 this.msgRef.current.valueconsole.log("value:", this.msgRef.current.value);//};render() {return (<div>{/* 给表单绑定一个ref属性 */}<input ref={this.msgRef} onChange={this.changeMsg} /></div>);}
}

控制台效果:

React教程(二):React组件基础相关推荐

  1. React学习二(组件详解)

    文章目录 一.React数据流 二.组件的特性 1.属性(props) (1)React Props默认值与标签属性限制 (2)应用-React组件切分与提取 2.状态(state) (1)state ...

  2. React Native 二 常用组件与开源组件

    2019独角兽企业重金招聘Python工程师标准>>> #0.手把手教React Native实战之开山篇##作者简介东方耀 Android开发RN技术 facebookgithub ...

  3. React教程(二)——jsx语法、条件渲染、列表渲染

    1.JSX 语法 在react中,就是使用jsx的语法,来实现DOM元素的展示.一个基本的jsx语法的react模板如下: <div>{this.props.title}</div& ...

  4. 【Cocos2d入门教程二】Cocos2d-x基础概念

    上一章已经学习了环境的搭建.这一章对基础概念进行掌握.内容大概有: 1.导演 2.场景 3.节点 4.层 4.精灵 1.导演(Director) 导演存在的主要作用: 环境设定(帧率 初始化openG ...

  5. Linux命令入门教程(二):目录基础篇

    2.1 目录及路径基础介绍 在linux中,目录(directory)通常也可表述为路径,一般不叫文件夹. 文件系统中,目录树的起点为根目录,任何路径都能以根目录来寻址. 以"/" ...

  6. vb.net 教程 11-1 打印组件 4 PrintDocument 4

    版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的. 上一节讲到了打印多张页面,本节谈谈使用自定义大小的纸张. 自定义纸张是通过设置PaperSize ...

  7. React教程(一):React基础

    传送门: React教程(二):React组件基础 一.React介绍 React是什么   一个专注于构建用户界面的javascript库,和vue和angular并称前端三大框架,不夸张的说,re ...

  8. 【Youtobe trydjango】Django2.2教程和React实战系列二【settings配置文件】

    [Youtobe trydjango]Django2.2教程和React实战系列二[settings配置文件] 1. Django项目初始化过程 2. 全貌 3. 详细解释 4. 增加其他配置 1. ...

  9. 前端React教程第三课 数据是如何在 React 组件之间流动

    04 数据是如何在 React 组件之间流动的?(上) 通过前面 3 个课时的学习,相信你已经对 React 生命周期相关的"Why""What"和" ...

最新文章

  1. 我使出这“三板斧”(分段锁、哈希锁、弱引用锁)灭霸跑了......
  2. 脑与认知科学2 脑神经电生理学上
  3. SpringBoot部署项目到Docker仓库
  4. 《版式设计——日本平面设计师参考手册》—第1章段落样式和字符样式的基础知识...
  5. Docker基本概念与实践(四)-部署简单web项目(tomcat+war+mysql)
  6. mysql post 注入工具类_【Mysql sql inject】POST方法BASE64编码注入write-up
  7. ubuntu环境下安装opencv教程及测试
  8. 【Cmake】Ctest测试工具
  9. st58服务器装系统,安装系统 - 微擎 - 公众平台自助开源引擎
  10. Acwing-4656. 技能升级
  11. 用互动的方式打开“11月全国气象短视频(快手、抖音)影响力榜单“
  12. 解决谷歌浏览器启动页面默认是搜狗浏览?
  13. 浏览器内置对象 Web API 规则部分
  14. jquery.SuperSlide
  15. K8S相同后端存储在2个K8S集群PVC数据直接拷贝
  16. javaweb学习笔记2(jquery的使用,以及常用的方法,选择器,过滤器)
  17. 普通大学生自学 JAVA 怎样才能进BAT大厂?
  18. asp.net ajax scriptmanager,ASP.NET: ScriptManager Enables AJAX In Your Web Apps | Microsoft Docs
  19. python-app自动化查找微信僵尸好友
  20. 信捷伺服刚性调整_伺服电机刚性怎么调整

热门文章

  1. VsCode安装和配置C++环境详细全流程
  2. php欢迎界面代码,分享微信小程序欢迎界面开发的实例代码
  3. 保定市2018-2019天气爬取
  4. 要辞职了,收集一些如何写辞职信的模板
  5. Exynos4412 移植针对Samsung的Linux-6.1(六)【已解决】SROMC寄存器的数值不正确、无法赋值的问题
  6. 几种maven仓库的优先级
  7. IDEA运行main方法报Command line is too long解决方法
  8. IBM x系列服务器光通路诊断灯错误解释
  9. 江苏大学计算机专业江苏排名,江苏大学算名校吗?江苏大学排名为啥这么高?...
  10. 实证分析matlab,《空间计量经济学——基于MATLAB的应用分析》书评