学习React
- 什么是React?
用于构建用户界面的JS库
react只关注视图(也就是页面)
AIA:是一个将数据渲染为HTML视图的开源JS库,感觉像是程序员和DOM之间的代理
- 步骤
- 发送请求获取数据
- 处理数据(过滤、整理格式)
- 操作DOM呈现页面
- 谁开发的?
由Facebook开发,且开源
软件工程师Jorda Walke创建
- 为什么用react
- 原生js操作DOM繁琐、效率低
- 使用JS直接操作DOM, 浏览器会进行大量的重绘重排
- 原生没有组件化编码方案,代码复用率低
- 采用组件化模式、声明式编码,提高开发效率及组件复用率
- 在React Native中可以使用React语法进行移动端开发
- 使用虚拟DOM+Diffing算法,减少与真实DOM交互
- babel.min.js (es6->es5 jsx->js)
- react.development.js(react核心库)
- react-dom.development(react扩展库)
虚拟DOM
虚拟DOM的两种创建方式
- 使用jsx创建虚拟虚拟DOM
- 格式
引入react核心库
引入react-dom,用于支持react操作DOM
引入babel
1 2 3 4 5 6 7 8 9 10 11
| <div id="test"></div> <div id="demo"></div>
<script type="text/babel">
const VDOM = <h1>Hello React</h1> const TDOM = document.getElementById('demo')
ReactDOM.render(VDOM,document.getElementById("test")) </script>
|
- 使用js创建虚拟DOM
- 格式
引入react核心库
引入react-dom,用于支持react操作DOM
1 2 3 4 5 6 7 8 9 10 11 12
| <div id="test"></div> <div id="demo"></div>
<script type="text/javascript">
const VDOM = React.createlement(标签名,标签属性,标签内容) const VDOM = React.createlement('h1',{id:'title'},'Hello React') const TDOM = document.getElementById('demo')
ReactDOM.render(VDOM,document.getElementById("test")) </script>
|
关于虚拟DOM
- console.log(VDOM instanceof Object) 本质是 Object 类型的对象
- 虚拟DOM比较”轻”,属性少。因为虚拟DOM是react内部在用,无需真实DOM那么多的属性
1 2 3
| console.log('虚拟DOM',VDOM) console.log('真实DOM',TDOM) debugger
|
- 虚拟DOM最终会被React转化为真实DOM,呈现在页面上
JSX简介
全称:javascript XML
是一个 JavaScript 的语法扩展。在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。
为什么使用JSX?
React 认为渲染逻辑本质上与其他UI逻辑内在耦合,比如
上述例子若是在h1标签中再加一个span标签:
1 2 3 4 5 6 7 8 9
| const VDOM = ( <h1 id="title"> <span>Hello React</span> </h1> )
const VDOM = React.createlement('h1',{id:'title'},React.createElement('span',{},'Hello React'))
|
BTW——XML
早期用于存储和传输数据
1 2 3 4 5 6 7
| <student> <name>Tom</name> <age>19</age> </student>
{"name":'Tom',"age":19}
|
BTW——json
- parse方法
- stringify方法
jsx语法规则
- 定义虚拟DOM时不要写引号
- 标签中混入js表达式时用{},myId,myData
[注意]区分js表达式 和 js语句(代码)
- 表达式一定会产生一个值,可以放在任何一个需要值的地方
下面这些都是表达式 :
.a,
.a+b
.demo(1)
arr.map(() => {return})
function test() {}
- 语句(代码)
下面这些都是语句(代码)
.if()
.for()
.switch() {case:xxx}
- 样式的类名指定不要用class,要用className
- 内联样式要用,style=两个大括号,里面写key:value的形式 去写
比如两个大括号,中间写color:’white’
- 虚拟DOM,只有一个根标签 在这个例子中所有东西都放h2里
- 标签必须闭合
- 标签首字母
(1)若小写字母开头,则将该标签转为html同名元素,若html中无该标签对应同名元素,则报错
(2)若大写字母开头,react就去渲染对应组件,若组件没有定义,则报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <style> .title { background:skyblue; } </style>
<script type="text/babel"> const myId = 'ALin' const myData = 'suibian'
const VDOM = ( <h1 id={myId.toLowerCase()} className='title'> <span>{myData.toLowerCase()}</span> </h1> ) ReactDOM.render(VDOM,document.getElementById('test')) </script>
|
例子:渲染数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script type="text/babel"> const data = ['Angular','React','Vue']
const VDOM = ( <div> <h1>前端js框架列表</h1> <ul> { data.map((item,index) =>{ return <li key={index}>{item}</li> // 这样写少了key值,可以暂时用index来代替,但最好还是用id,因为index会变化 }) } </ul> </div> ) </script>
|
模块与组件、模块化与组件化的理解
模块
- 向外提供特定的js程序,一般就是一个js文件
- 为什么要拆成模块?
随着业务逻辑增加,代码越来越多越来越复杂
- 作用:复用js,提高js运行效率
组件
- 用来实现局部功能效果的代码和资源集合(html/css/image/js)
- 为什么要拆成组件?
一个界面功能更复杂
- 作用:复用代码,简化项目编码,提高运行效率
模块化
当应用的js都以模块来编写的,这个应用就是一个模块化应用
组件化
当应用是以多组件的方式实现,这个应用就是一个组件化的应用
react面向组件编程
两种定义组件方式
- 函数式组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="test"></div>
<script type="text/babel">
function Demo() { console.log(this) return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2> }
ReactDOM.render(<Demo/>,document.getElementById('test')) 这样写会报错,不能直接写demo
</script>
|
- 类式组件
回顾一下es6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| class Person { constructotr(name,age) { this.name = name this.age = age } speak() { speak方法放在哪里了? 类的原型对象上 speak方法给谁用的?给实例用 speak中this是谁?p1/p2 通过Person实例调用speak时,speak中的this就是Person实例 console.log(`我叫${this.name},我年龄是${this.age}`) } }
const p1 = new Person('tom',19) const p2 = new Person('jerry',17) console.log(p1) console.log(p2) p1.spaek() p2.speak()
class Student extends Person { constructor(name,age,grade) { super(name,age) this.grade = grade } speak() { console.log(`我叫${this.name},我年龄是${this.age},我是${this.grade}年级`) } study() { console.log('我很努力的学习') } } const s1 = new Student('小张',15,'高一') console.log(s1)
|
【AIA】
- 类中的构造器不是必须写,要对实例进行一些初始化操作,如指定添加属性时才写(比如grade)
- 如果A类继承B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的
- 类中所定义的方法,都是放在类的原型对象上,供实例使用
创建类式组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <div id="test"></div> <script type="text/babel"> class MyComponent extends React.Component { render() { return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2> } } ReactDOM.render(<MyComponent/>,document.getELementById('test'))
</script>
|
组件三大属性
第一————组件的状态
- 像es6一样,我需要用到实例中的state,但天默认是空值,就是空对象。需要自己添加,所以用到constructor和super
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <div id="test"></div> <script type="text/babel"> class Weather extends React.Component { constructor(props) { super(props) this.state={isHot:true} } render() { const {isHot} = this.state return <h1>今天天气{isHot ? '炎热' : '凉爽'}!</h1> } } ReactDOM.render(<Weather/>,document.getELementById('test'))
</script>
|
- 事件绑定
回顾一下原生事件绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <button>btn1</button> <button>btn2</button> <button onclick="demo()">btn3</button>
<script type="text/javascript"> const btn1 = document.getElementById('btn1') btn1.addEventListener('click',() => { alert('按钮1被点击了') })
const btn2 = document.getElementById('btn2') btn2.onclick = (() => { alert('按钮1被点击了') })
function demo() { alert('按钮3被点击了') } </script>
|
- react事件绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <div id="test"></div> <script type="text/babel"> let that class Weather extends React.Component { constructor(props) { super(props) this.state={isHot:true} that = this this.changeWeather = this.changeWeather.bind(this) } render() { const {isHot} = this.state return <h1 onClick={this.changeWeather} >今天天气{isHot ? '炎热' : '凉爽'}!</h1> } changeWeather() { console.log(this.state.isHot) } } ReactDOM.render(<render/>,document.getELementById('test')) const title = document.getElementById('title')
title.addEventListener("click",() => { console.log('标题被点击') }) title.onclick = () => { console.log('标题被点击') } function changeWeather() { const {isHot} = this.state console.log(isHot)
console.log(that.state.isHot) } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Person { constructor(name,age) { this.name = name this.age = age } study() { console.log(this) } } const p1 = new Person('tom',19) p1.study() const x = p1.study x()
|
- setState 应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <div id="test"></div> <script type="text/babel"> class Weather extends React.Component {
console.log(constructor) constructor(props) { super(props) this.state={isHot:true,wind:'微风'} this.changeWeather = this.changeWeather.bind(this) }
console.log(render) render() { const {isHot} = this.state return <h1 onClick={this.changeWeather} >今天天气{isHot ? '炎热' : '凉爽'}!,{wind}</h1> }
console.log(render) changeWeather() { const isHot = this.state.isHot this.setState({isHot:!isHot}) console.log(this.state.isHot) } } ReactDOM.render(<Weather/>,document.getELementById('test')) </script>
|
- 上述代码精简方式
类中可以直接写赋值语句不需要let什么的声明,直接a=1
所以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <div id="test"></div> <script type="text/babel"> class Weather extends React.Component { state={isHot:true,wind:'微风'} render() { const {isHot} = this.state return <h1 onClick={this.changeWeather} >今天天气{isHot ? '炎热' : '凉爽'}!,{wind}</h1> }
changeWeather = () => { const isHot = this.state.isHot this.setState({isHot:!isHot}) console.log(this) } } ReactDOM.render(<Weather/>,document.getELementById('test')) </script>
|
【AIA】
- state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)
- 组件被称为“状态机”,像生活中的红绿灯,通过更新组件的state来更新对应的页面显示(重新渲染组件)
[注意]
- 组件中render方法中的this为组件的实例对象
- 组件自定义方法中的this都是undefined,如何解决?
a. 强制绑定this:通过函数对象的bind()
b. 箭头函数
- 状态数据不能直接修改或更新
组件的第二个属性————props
类里面的this指向组件的实例对象,里面有一个props空对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <div id="test"></div> <script type="text/babel"> class Person extends React.Component { render() { const {name,age,sex} = this.props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age}</li> </ul> ) } } ReactDOM.render(<Person name="tom" sex="男" age="18" />,document.getELementById('test')) const p = {name="tom" sex="男" age="18"} ReactDOM.render(<Person name={p.name} sex={p.sex} age={p.age} />,document.getELementById('test')) ReactDOM.render(<Person {...p}/>,document.getELementById('test')) console.log(...p) </script>
|
回顾一下扩展运算符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| let arr1 = [1,2,3,4,5] let arr2 = [2,4,6,8,10] console.log(...arr1) console.log(arr1)
let arr3 = [...arr1,...arr2] console.log(arr3)
function sum(a+b) { return a+b } console.log(sum(1,2))
function sum(...numbers) { console.log(numbers) return numbers.reduce((preValue,currentValue) => { return preValue + currentValue }) } console.log(sum(1,2))
let person = {name:'tom',age:'18'} console.log(...person)
let person = {name:'tom',age:'18'} let person2 = {...person} person.name = 'jerry' console.log(person2) console.log(person)
let person3 = {...person,name:'jack',address:'地球'} console.log(person3)
|
props有一些限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <div id="test"></div> <script type="text/babel"> class Person extends React.Component { render() { const {name,age,sex} = this.props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age + 1}</li> </ul> ) } }
Person.propsTypes = { name:PropTypes.string.isRequired, sex:PropTypes.string, age:PropTypes.number, speak:PropTypes.func } Person.defaultProps = { sex:'男', age:18 } ReactDOM.render(<Person name="tom" sex="男" age={18} speak={speak}/>,document.getELementById('test'))
function speak() { console.log('我在讲话') } </script>
|
- 姓名必须指定,且为字符串类型
- 性别为字符串类型,如果性别没有指定,默认为男
- 年龄为字符串类型,且为数字类型,默认值为18
props的简写方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <div id="test"></div> <script type="text/babel"> class Person extends React.Component { static propsTypes = { name:PropTypes.string.isRequired, sex:PropTypes.string, age:PropTypes.number, speak:PropTypes.func } static defaultProps = { sex:'男', age:18 } render() { const {name,age,sex} = this.props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age + 1}</li> </ul> ) } }
ReactDOM.render(<Person name="tom" sex="男" age={18} speak={speak}/>,document.getELementById('test'))
function speak() { console.log('我在讲话') } </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <div id="test"></div> <script type="text/babel"> constructor(props) { super(props) console.log(this.props) } class Person extends React.Component { static propsTypes = { name:PropTypes.string.isRequired, sex:PropTypes.string, age:PropTypes.number, speak:PropTypes.func } static defaultProps = { sex:'男', age:18 } render() { const {name,age,sex} = this.props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age + 1}</li> </ul> ) } }
ReactDOM.render(<Person name="tom"/>,document.getELementById('test')) </script>
|
函数组件使用props
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <div id="test"></div> <script type="text/babel"> function Person() { const {name,age,sex} = props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age}</li> </ul> ) } Person.propsTypes = { name:PropTypes.string.isRequired, sex:PropTypes.string, age:PropTypes.number } Person.defaultProps = { sex:'男', age:18 } ReactDOM.render(<Person name="jerry" sex="男" age={18}/>,document.getElementById('test')) </script>
|
组件的第三个属性————ref
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| <div id="test"></div> <script type="text/babel"> class Demo extends React.Component { showData = () => {
console.log(this.refs.input1) const {input1} = this.refs alert(input1.value) } showData2 = () => { const {input2} = this.refs alert(input2.value) }
showData = () => {
console.log(this.refs.input1) const {input1} = this alert(input1.value) } showData2 = () => { const {input2} = this alert(input2.value) } render() { return (
<div> {/* <input type="text" ref={(a)=> {console.log(a)} }placeholder="点击按钮提示数据"/> */} {/* 这个a,打印出来后是 <input type="text" placeholder="点击按钮提示数据"/> ref属性当前所在的节点 */} {/* <input type="text" ref={(a)=> {this.input1 = a} }placeholder="点击按钮提示数据"/> */} {/* 把a这个节点放在组件实例自身上 */}
<input type="text" ref={currentNode => this.input1 = currentNode }placeholder="点击按钮提示数据"/> <button onClick={this.showData}>点我提示左侧数据</button> <input type="text" onBlur={this.showData2} ref={c => this.input2 = c} placeholder="失去焦点提示数据"/> </div> ) } }
ReactDOM.render(<Demo/>,document.getELementById('test')) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <div id="test"></div> <script type="text/babel"> class Demo extends React.Component { showInfo = () => { const {input1} = this alert(input1.value) } changeWeather = () => { state = {isHot:true} this.setState({isHot:!isHot}) } saveInput = (c) => { this.input1 = c console.log('@',c) } render() { const {isHot} = this.state return ( <div> <h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2> {/* <input ref={c => this.input1 = c;console.log('@',c)}/> */} {/* 解决第一次传入参数null,第二次会传入参数DOM元素 通过ref回调函数定义成class的绑定函数方式*/} <input ref={this.saveInput} type="text"/> <button onClick={this.showInfo}>点我提示输入的数据</button> <button onClick={this.changeWeather}>点我切换天气</button> </div> ) } }
ReactDOM.render(<Demo/>,document.getELementById('test')) </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <div id="test"></div> <script type="text/babel"> class Demo extends React.Component {
myRef = React.createRef() myRef2 = React.createRef() showData = () => { console.log(this.myRef) console.log(this.myRef.current) console.log(this.myRef.current.value) } showData2 = () => { console.log(this.myRef2.current.value) } render() { return ( <div> <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/> {/* input被存在this.myRef中 */} <button onClick={this.showData}>点我提示左侧的数据</button> <input ref={this.myRef2} type="text" onBlur={this.showData2} placeholder="点击按钮提示数据"/> </div> ) } } ReactDOM.render(<Demo/>,document.getELementById('test')) </script>
|
react中的事件处理
- 通过onXXX属性指定事件处理函数(注意大小写)
- react使用的是自定义(合成)事件,而不是使用的原生DOM事件————为了更好的兼容
- react中事件是通过事件委托方式处理的(委托给组件最外层元素)————为了高效
- 通过event.target得到发生事件的DOM元素(不要过度使用Refs,可以用这个代替)
1 2 3 4 5 6 7
| showData = () => { console.log(this.myRef2.current.value) } showData = (event) => { console.log(event.target.value) }
|
受控组件,非受控组件
- 非受控组件
通过手动操作dom方式获取文本框的值,文本框状态不受react组件的state中状态控制,直接通过原生dom获取输入框的值
实现步骤:
- 导入createRef函数
- 调用createRef函数,创建一个ref对象,存储到名为msgRef的实例属性中
- 为input添加ref属性,只为msgRef
- 在按钮的事件处理程序中,通过msgRef.current即可拿到input对应的dom元素,而其中msg.current.value拿到的就是文本框的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import React,{createRef} from "react" class Input extends React.Component { msgRef = createyRef() getValue=() => { console.log(this.msgRef.current.value) } render() { return ( <> <input type="text" ref={this.msgRef}/> <button onClick={this.getValue}>点击获取输入框的值</button> </> ) } }
|
这并不是react特有的行为,这其实与javascript函数工作原理有关。通常情况下,如果你没有在方法后面添加(),例如onClick={this.handleClick},你应为这个方法绑定this
- 受控组件
input框自己的状态被react组件控制
受控组件就是说可以被react动态控制的组件
实现步骤:
- 在组件的state中声明一个组件的状态数据
- 将状态数据设置为input标签元素的value属性的值
- 为input添加onchange事件
- 在事件处理程序中,通过事件对象e获取到当前文本框的值(即用户当前输入的值)
- 调用setState方法,将文本框的值作为state状态的最新值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Counter extends React.Component { state = { message:'this is a message' } inputChange = (e) => { console.log('change事件触发了',e) this.setState({ message:e.target.value }) } render() { return ( <input type="text" value={this.state.message} onChange={this.inputChange}/> ) } }
|
优化上述代码
若有很多个input,比如用户名,密码等等,总不能绑定一个又一个onchange事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class Counter extends React.Component { state = { username:'', password:'' }
saveFormData = (dataType) => { console.log(dataType) return (e) => { console.log(e.target.value) this.setState({
[dataType]:e.target.value }) } }
handleSubmit = (e) => { e.preventDefault() const {username,password} = this.state alert(`用户名是${username}`,密码是${password}) } render() { return ( <form onSubmit={this.handleSubmit}> 用户名<input type="text" onChange={this.saveFormData('username')}/> {/* 但若是这么写就是把saveFormData返回值作为回调,立即执行 saveFormData返回值是undefined */} 密码<input type="text" onChange={this.saveFormData('password')}/> </form> ) } }
|
高阶函数和函数柯里化
- 上述saveFormData这就是高阶函数
高阶函数:
如果一个函数符合下面两个规范中的任何一个,那该函数就是高阶函数
1. 若A函数接收的参数是一个函数,那么A就可以称之为高阶函数
2. 若A函数调用的返回值依然是一个函数,那么A就可以称之为高阶函数
常见的高阶函数:
promise、setTimeout、arr.map()等等
- 函数柯里化
通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式
1 2 3 4 5
| function sum(a,b,c) { return a+b+c } const result = sum(1,2,3) console.log(sum )
|
不用柯里化实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
saveFormData = (dataType,e) => { this.setState({[dataType]:e.target.value}) }
render() { return (
<form onSubmit={this.handleSubmit}> 用户名<input type="text" onChange={(e) => {this.saveFormData('username',e)}}/> {/* 但若是这么写就是把saveFormData返回值作为回调,立即执行 saveFormData返回值是undefined */} 密码<input type="text" onChange={(e) => {this.saveFormData('password',e)}}/> </form> ) }
|
react生命周期
生命周期回调函数 又叫 生命周期钩子函数 生命周期钩子 生命周期函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <div id="test"></div> <script type="text/babel"> class Life extends React.Component { state = {opacity:1} death = () => { clearInterval(this.timer) ReactDOM.unmountComponentAtNode(document.getElementById('test')) }
componentDidMount() { this.timer = setInterval(() => { let {opacity} = this.state opacity -= 0.1 if(opacity <=0) opacity = 1 this.setState ({opacity}) },200) }
render() { return ( <div> {/* h2中写style={{opacity:this.state.opacity}} */} <h2>只要学不死,就往死里学</h2> <button onClick={this.death}>不活了</button> </div> ) } }
ReactDOM.render(<Life/>,document.getELementById('test')) </script>
|
- 组件是否应该被更新shouldComponentUpdate
true可以更新
false不可以更新
不写这个钩子,默认true
- forceUpdate强制更新
可以绕过shouldComponentUpdate,直接进行更新
父组件render
componentWillReceiveProps这个第一次传的不算,以后传的才算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class A extends React.Component{ state = {carName:'宝马'} changeCar = () => { this.setState({carName:'奔驰'}) } render() { return ( <div> <div>我是A组件</div> <button onClick={this.changeCar}></button> <B carName={this.state.carName}/> </div> ) } } class B extends React.Component{ componentWillReceiveProps(props) { console.log('B---componentWillReceiveProps',props) } render() { return ( <div> <div>我是B组件,接收的车是:{this.props.carName}</div> </div> ) } }
|
[AIA]
- 初始化阶段: 由ReactDoM.render()触发—初次渲染
constructor()
componentWillMount()
render()
- componentDidMount()更新阶段: 由组件内部this.setSate()或父组件重新render触发
shouldComponentUpdate()componentwillUpdate()
render()
componentDidUpdate()
- 卸载组件:由ReactDOM.unmountComponentAtNode()触发componentwillUnmount()
新生命周期
去掉三个钩子,加了两个钩子
componentWillMount() componentwillUpdate() componentwillUnmount()
- getDerivedStateFromProps:若state的值任何时候都取决于props,可以使用
- getSnapShotBeforeUpdate(preProps,preState,snapValue) 在更新前获取快照
在页面调完时拿到数据在处理时使用,此生命周期的任何返回值将作为参数传递给componentDidUpdate