[React] 尚硅谷 -- 学习笔记(二)
第二章 React面向组件编程
基本理解和使用
自定义组件
定义组件
- 工厂函数组件(
简单组件
)
function MyComponent () {return <h2>工厂函数组件(简单组件)</h2> }
没有状态的组件
- ES6类组件(
复杂组件
)
class MyComponent2 extends React.Component {render () {console.log(this) // MyComponent2的实例对象return <h2>ES6类组件(复杂组件)</h2>} }
- 工厂函数组件(
渲染组件标签
ReactDOM.render(<MyComponent />, document.getElementById('example1'))
注意事项
组件名必须首字母大写
虚拟DOM元素只能有一个根元素
虚拟DOM元素必须有结束标签
组件三大属性(state)
state是组件对象最重要的属性, 值是对象(可以包含多个数据)
组件被称为"
状态机
", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
操作
- 初始化状态
constructor (props) {super(props)// 初始化状态this.state = {isLikeMe: true}
- 读取某个状态->绑定this为组件对象
this.change = this.change.bind(this)
- 更新状态->组件界面更新
this.setState({isLikeMe: !this.state.isLikeMe
})
组件三大属性(props)
每个组件对象都会有props(properties的简写)属性
组件标签的所有属性都保存在props中
操作
- 内部读取某个属性值
this.props.propertyName
- 对props中的属性值进行类型限制和必要性限制
Person.propTypes = {name: PropTypes.string.isRequired,sex: PropTypes.string,age: PropTypes.number
}
- 扩展属性: 将对象的所有属性通过props传递
<Person {...person}/>
...
的作用:
打包
function fn(...as) {} fn( 1,2,3)
解包
const arr1 =[1,2,3] const arr2 = [6, ...arr1, 9]
- 默认属性值
Person.defaultProps = {sex: '男',age: 18
}
- 组件类的构造函数
constructor (props) {super(props)console.log(props) // 查看所有属性
}
props和state属性区别
props | state |
---|---|
用于定义外部接口 | 用于记录内部状态 |
赋值在于外部世界使用组件 | 赋值在于组件内部 |
不改变组件值 | 让组件来修改的 |
不能在constructor中设置默认值 | 只能在constructor中设置默认值 |
从组件外部向组件内部传递数据, 组件内部只读不修改 | 组件自身内部可变化的数据 |
none | setState修改值为异步的 |
组件三大属性(refs与事件处理)
//定义组件class MyComponent extends React.Component {constructor(props) {super(props) // 调用父类(Component)的构造函数//console.log(this)// 将自定义的函数强制绑定为组件对象this.showInput = this.showInput.bind(this) // 将返回函数中的this强制绑定为指定的对象, 并没有改变原来的函数中的this}// 自定义的方法中的this默认为nullshowInput() {// alert(this) //this默认是null, 而不是组件对象// 得到绑定在当前组件对象上的input的值alert(this.msgInput.value)}handleBlur(event) {alert(event.target.value)}render() {return (<div><input type="text" ref={input => this.msgInput = input}/>{' '}<button onClick={this.showInput}>提示输入数据</button>{' '}<input type="text" placeholder="失去焦点提示数据" onBlur={this.handleBlur}/></div>)}}// 渲染组件标签ReactDOM.render(<MyComponent/>, document.getElementById('example'))
refs属性
组件内的标签都可以定义ref属性来标识自己
<input type="text" ref={input => this.msgInput = input}/>
回调函数在组件初始化渲染完或卸载时自动调用
在组件中可以通过this.msgInput来得到对应的真实DOM元素
作用: 通过ref获取组件内容特定标签对象, 进行读取其相关数据
事件处理
通过onXxx属性指定组件的事件处理函数(注意大小写)
React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
通过event.target得到发生事件的DOM元素对象
<input onFocus={this.handleClick}/>handleFocus(event) {event.target //返回input对象
}
注意
组件内置的方法中的this为组件对象
在组件类中自定义的方法中this为null
强制绑定this: 通过函数对象的bind()
箭头函数(ES6模块化编码时才能使用)
组件的组合
流程
- 拆分组件: 拆分界面,抽取组件
- 实现静态组件: 使用组件实现静态页面效果(只有静态界面,没有动态数据和交互)
- 实现动态组件
- 实现动态显示初始化数据
- 交互功能(从绑定事件监听开始)
问题1:数据保存在哪个组件内?
看数据是某个组件需要(给它),还是某些组件需要(给共同的父组件)
问题2:需要在子组件中改变父组件的状态
子组件中不能直接改变父组件的状态
状态在哪个组件,更新状态的行为就应该定义在哪个组件
解决:父组件定义函数,传递给子组件,子组件调用
<script type="text/babel">class App extends React.Component {constructor(props) {super(props)// 初始化状态this.state = {todos: ['吃饭', '睡觉', '打豆豆']}this.addTodo = this.addTodo.bind(this)}addTodo(todo) {const {todos} = this.statetodos.unshift(todo)//更新状态this.setState({todos})}render() {const {todos} = this.statereturn (<div><h1>Simple TODO List</h1><Add count={todos.length} addTodo={this.addTodo}/><List todos={todos}/></div>)}}class Add extends React.Component {constructor(props) {super(props);this.add = this.add.bind(this)}add() {// 读取输入数据const todo = this.todoinput.value.trim()// 检查合法性if (!todo) {return}// 保存到todosthis.props.addTodo(todo)// 清除输入this.todoinput.value = ''}render() {return (<div><input type="text" ref={input => this.todoinput = input}/><button onClick={this.add}> add #{this.props.count + 1}</button></div>)}}Add.propTypes = {count: PropTypes.number.isRequired,addTodo:PropTypes.func.isRequired}class List extends React.Component {render() {const {todos} = this.propsreturn (<ul>{todos.map((todo, index) => {return <li key={index}>{todo}</li>})}</ul>)}}List.propTypes = {todos: PropTypes.array.isRequired,}// 渲染应用组件标签ReactDOM.render(<App/>, document.getElementById('example'))</script>
收集表单数据
包含表单的组件分类
受控组件: 表单项输入数据能自动收集成状态
非受控组件: 需要时才手动读取表单输入框中的数据
效果
<script type="text/babel">class LoginForm extends React.Component {constructor(props) {super(props)// 初始化状态this.state = {username: ''}this.handleSubmit = this.handleSubmit.bind(this)this.handleChange = this.handleChange.bind(this)}handleChange(event) {this.setState({username: event.target.value})}handleSubmit(event) {alert(`准备提交的用户名为: ${this.state.username}, 密码:${this.pwdInput.value}`)// 阻止事件的默认行为: 提交表单event.preventDefault()}render() {return (<form onSubmit={this.handleSubmit} action="/test"><label>用户名:<input type="text" value={this.state.username} onChange={this.handleChange}/></label> <label>密码:<input type="password" ref={(input) => this.pwdInput = input}/></label> <input type="submit" value="登陆"/></form>)}}ReactDOM.render(<LoginForm/>, document.getElementById('example'))
</script>
组件生命周期
生命周期表
效果
组件对象从创建到死亡它会经历特定的生命周期阶段
React组件对象包含一系列的勾子函数(生命周期回调函数), 在生命周期特定时刻回调
<script type="text/babel">class Fade extends React.Component {constructor (props) {super(props)console.log('constructor(): 创建组件对象')this.state = {opacity: 1}this.removeComponent = this.removeComponent.bind(this)}componentWillMount () {console.log('componentWillMount(): 初始化将要挂载')}componentDidMount () {// 在此方法中启动定时器/绑定监听/发送ajax请求console.log('componentDidMount(): 初始化已经挂载')// 保存到当前组件对象中this.intervalId = setInterval(function () {// 得到当前opacitylet {opacity} = this.state// 更新opacityopacity -= 0.1if(opacity<=0) {opacity = 1}// 更新状态this.setState({opacity})}.bind(this), 200)}componentWillUpdate () {console.log('componentWillUpdate(): 将要更新')}componentDidUpdate () {console.log('componentDidUpdate(): 已经更新')}componentWillUnmount () {// 清除定时器/解除监听console.log('componentWillUnmount(): 将要被移除')clearInterval(this.intervalId)}removeComponent () {ReactDOM.unmountComponentAtNode(document.getElementById('example'))}render() {console.log('render() 渲染组件')return (<div><h2 style={{opacity:this.state.opacity}}>{this.props.content}</h2><button onClick={this.removeComponent}>不活了</button></div>)}}ReactDOM.render(<Fade content="react学不会, 怎么办?"/>, document.getElementById('example'))
</script>
生命周期流程图
组件对象从创建到死亡它会经历特定的生命周期阶段
React 组件对象包含一系列的钩子函数(生命周期回调函数),在生命周期特定时刻回调
我们在定义组件时,可以重写特定的生命周期回调函数,做特定的工作
生命周期详述
- Mount:挂载过程,第一次将组件插入到真实 DOM
- Update:更新过程,组件被重新渲染
- Unmount:卸载过程,被移出真实 DOM
生命周期流程
1)创建阶段(第一次初始化渲染显示)
ReactDOM.render()
constructor():
super(props)
指定 this,this.state={}
创建初始化状态(getDefaultProps、getInitialState)componentWillMount()
:组件将要挂载到页面上
- 可以在这里调用 setState() 方法修改 state
render():创建虚拟 DOM 但是还没有挂载上去
componentDidMount()
:已经挂载到页面上(初始界面已经渲染完毕)
- 可以在这里通过 this.getDOMNode() 来进行访问 DOM 结构
- 可以在这里发送 ajax 请求
- 添加监听器/订阅
2)运行阶段(二次渲染)
父组件传递的
props
发生更新,就会调用 componentWillReceiveProps()
- componentWillReceiveProps(nextProps):当子组件接受到 nextProps 时,不管这个 props 与原来的是否相同都会调用
props
改变或者调用 this.setState() 方法更新state
,都会触发组件的更新,调用后面的钩子函数
- shouldComponentUpdata(nextProps, nextState):接收一个新的 props 和 state,返回true/false,表示是否允许更新
- 通常情况下为了优化,需要对新的 props 以及 state 和原来的数据作对比,如果发生变化才更新
调用 this.forceUpdate() 方法会直接进入 componentWillUpdate。跳过 shouldComponentUpdate()
- componentWillUpdate():将要更新
- render():重新渲染
- componentDidUpdate():已经完成更新
除了首次 render 之后调用 componentDidMount
,其它 render 结束之后都是调用 componentDidUpdate
3)销毁阶段(移除组件)
执行 ReactDOM.unmountComponentAtNode(containerDom) 用来使组件从真实 DOM 中卸载(开始销毁阶段)
- componentWillUnmount():组件将要被移除时(移出前)回调
- 一般在
componentDidMount
里面注册的事件需要在这里删除
- 一般在
重要勾子
- render():初始化渲染时或更新渲染时调用
- componentDidMount():开启监听,可以初始化一些异步操作:启动定时器/发送 ajax 请求
- componentWillUnmount():做一些收尾工作,如:清理定时器
- componentWillReceiveProps():当组件接收到(父元素传递的)新的 props 属性前调用
虚拟DOM与DOM Diff算法
效果
<script type="text/babel">class HelloWorld extends React.Component {constructor(props) {super(props)this.state = {date: new Date()}}componentDidMount () {setInterval(() => {this.setState({date: new Date()})}, 1000)}render () {console.log('render()')return (<p>Hello, <input type="text" placeholder="Your name here"/>! <span>It is {this.state.date.toTimeString()}</span></p>)}}ReactDOM.render(<HelloWorld/>,document.getElementById('example'))
</script>
基本原理图
[React] 尚硅谷 -- 学习笔记(二)相关推荐
- [React] 尚硅谷 -- 学习笔记(一)
第一章 React入门 React基本认识 用于构建用户界面的 JavaScript 库(View) 官网 英文官网: https://reactjs.org/ 中文官网: https://doc.r ...
- [React] 尚硅谷 -- 学习笔记(七)
第七章 react-ui 最流行的开源React UI组件库 material-ui(国外) 官网 GitHub ant-design(国内蚂蚁金服) PC官网 GitHub 移动官网 GitHub ...
- [React] 尚硅谷 -- 学习笔记(六)
第六章 react-router4 理解 react-router react的一个插件库 专门用来实现一个SPA应用 基于react的项目基本都会用到此库 SPA 单页Web应用(single pa ...
- [React] 尚硅谷 -- 学习笔记(四)
第四章 react ajax 理解 React本身只关注于界面, 并不包含发送ajax请求的代码 前端应用需要通过ajax请求与后台进行交互(json数据) react应用中需要集成第三方ajax库( ...
- [React] 尚硅谷 -- 学习笔记(三)
第三章 react应用(基于react脚手架) 使用create-react-app创建react应用 react脚手架 xxx 脚手架:用来帮助程序员快速创建一个基于 xxx 库的模板项目 包含了所 ...
- [React] 尚硅谷 -- 学习笔记(五)
第五章 总结 组件间通信 通过props传递 共同的数据放在父组件上, 特有的数据放在自己组件内部(state) 通过props可以传递一般数据和函数数据, 只能一层一层传递 一般数据–>父组件 ...
- Java 基础 第3阶段:高级应用——尚硅谷学习笔记(含面试题) 2023年
Java 基础 第 3 阶段:高级应用--尚硅谷学习笔记(含面试题) 2023 年 Java 基础 第 3 阶段:高级应用--尚硅谷学习笔记(含面试题) 2023 年 第 9 章 异常处理 9.1 异 ...
- B站MySQL(尚硅谷)学习笔记
B站MySQL基础(尚硅谷)学习笔记 最近在学习数据库技术,并且把视频中的知识点进行了汇总,字数较多,仅供参考. 会持续更新 欢迎读者提出问题与错误,一起交流~ 视频前几集所讲述的基本知识: DB:数 ...
- 8-zookeeper算法基础(尚硅谷学习笔记)
目录 拜占庭将军问题 paxos算法 paxos算法流程 情况一 情况二 情况1 情况2 ZAB协议 ZAB协议内容 消息广播 过程 可能出现的问题 崩溃恢复 异常假设 leader选举 数据恢复 C ...
最新文章
- 2011年云计算发展趋势的五大预测
- switch-case和if-else可互换时
- 分布式系统架构与云原生—阿里云《云原生架构白皮书》导读
- 桌面鼠标手写输入法_「桌面分享」工作娱乐两不误,花费7万打造的桌面都有些啥?...
- 机器学习中的数学知识(part1)
- LLVM与Codegen技术
- MDP马尔可夫决策过程(二)
- 一个用js写的接口http调试程序
- Excel2016保存文件闪退(在安装了Visio后)
- MBA-day12 逻辑学-关系判断
- matlab中solver函数_Matlab中solve函数用法详解
- SDN是什么东东???
- Markdown常用样式
- SEO优化-SEO具体方法,SEO干货分享
- 场景设计题 汇总 (一)
- mysql 3306_允许远程链接mysql,开放3306端口
- PCB应力应变测试-ICT、FCT治具应力把控标准
- 了不起的Node.js: 将JavaScript进行到底(Web开发首选,实时,跨多服务器,高并发)...
- cuteftp不能连接虚拟机的解决方法
- 解决绝对定位留下来的空白
热门文章
- android倒计时动画特效,Android仿活动时分秒倒计时效果
- 部编版是什么版本_教材部编版和人教版的区别
- excel和mysql php_php将mysql数据库和Excel相互导入和导出的方法
- huffman图像编码C语言,Huffman编码的c语言实现
- MYSQL 批量Insert ID顺序生成(仿雪花算法)
- NETSTAT 指令详解
- Android SDK实例之Snake游戏深入解析(一)
- 概率图模型更进一步的知识点
- javaweb项目得执行过程及servlet得请求(Httprequest)和响应(Httpresponse)
- 8.5-Day1T1--Asm.Def 谈笑风生