一,组件的类型
1.React的组件类型可以分为函数式组件和类式组件:
1.函数式组件是通过定义函数return对应dom建构并通过render函数进行渲染的组件,通常用于简单组件。其结构如下:
function MyComponent(){
console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
2.类式组件是通过继承React.Component
并通过render函数进行渲染的组件,通常用于复杂组件。其结构如下:
class MyComponent extends React.Component {
render(){
//render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
//render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
console.log('render中的this:',this);
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
以上两种类型是react组件的静态组件。如果需要实现通过外部数据来渲染的动态组件,还需要其他的内容来辅助实现。
由此react引入组件实例的三大属性:state,props,refs。但若在不引入react hooks的情况下,类式组件能拥有这三个属性,而函数式组件则只有props属性(因为props相当于函数的参数)。
2.受控组件和非受控组件:
主要是针对表单做的一次细分,定义是受控组件还是非受控组件主要看的是组件的表单元素(如<input>
、 <textarea>
和 <select>
)是否实现了双向绑定,即不通过ref去实现输入与数据的实时变化,而是通过event.target去实现。
二,组件的属性
在开始学习三大属性前,先学习一下类式组件未简写时的结构,这里需要你懂得ES6中class,箭头函数,以及this指向等知识,若不清楚,请先去复习相关知识再继续阅读效果更佳。
那么,这里用一段代码来表示未简写的类式组件:
//1.创建组件
class Weather extends React.Component{
//构造器调用几次? ———— 1次
constructor(props){
console.log('constructor');
super(props)//写constructor时,需在定义其他属性前先super,不然可能会导致后面的属性未定义
//初始化状态
this.state = {isHot:false,wind:'微风'}
//解决changeWeather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
}
//render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
render(){
console.log('render');
//读取状态
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//changeWeather调用几次? ———— 点几次调几次
changeWeather(){
//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
console.log('changeWeather');
//获取原来的isHot值
const isHot = this.state.isHot
//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot:!isHot})
console.log(this);//不会输出内容
//严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
//this.state.isHot = !isHot //这是错误的写法
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
接下来是简写形式的类式组件,即属性state的例子:
//1.创建组件
class Weather extends React.Component{
//初始化状态
state = {isHot:false,wind:'微风'}
render(){
//组件中render方法中的this为组件实例对象
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//自定义方法————要用赋值语句的形式+箭头函数
changeWeather = ()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot})
console.log(this);//不会输出内容
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
类式组件的写法类似于ES6中的class写法,render函数内的return是jsx的语法糖,使用箭头函数的特性,可以获取到当前定义位置的父作用域,因此可以通过this获取到当前类的state属性。
state在使用时的一些规则:
1.状态(state)是不可直接更改,若要更改,需使用setState来更改,如this.setState({isHot:!isHot})
,此时的set是合并而不是替换,wind:'微风'
属性仍然存在。
2.state的更新会导致页面相关内容的重新渲染。
属性props的类式组件例子(已简化):
<script type="text/javascript" src="../js/prop-types.js"></script>
//创建组件
class Person extends React.Component{
//构造器constructor是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
//对标签属性进行类型、必要性的限制
static propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
//指定默认标签属性值
static defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
render(){
// console.log(this);
const {name,age,sex} = this.props
//props是只读的
//this.props.name = 'jack' //此行代码会报错,因为props是只读的
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
属性props的函数式组件例子(已简化):
<script type="text/javascript" src="../js/prop-types.js"></script>
//创建组件
function Person (props){
const {name,age,sex} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
props在使用时的一些规则:
1.使用props时,若需要对prop做限制,需要引入prop-types.js
,并使用如例子中的方式对属性做限制。
2.以后学习到其他的了再补充,哈哈哈
对于refs来说,则有三种形式,分别是:
1.字符串形式的ref<input ref="input1"/>
2.回调形式的ref<input ref={(c)=>{this.input1 = c}}
3.createRef创建ref容器
myRef = React.createRef()
<input ref={this.myRef}/>
注:若ref使用回调函数形式且内联到jsx中,则每次更新页面时相关的ref回调函数也会被再执行一次(因为是内联回调,所以更新时会重新执行,而不是被缓存起来),但是在日常开发时是无关紧要的事情。
举个refs的例子:
//创建组件
class Demo extends React.Component{
/*
React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的
*/
myRef = React.createRef()
//展示左侧输入框的数据
showData = ()=>{
const {input1} = this.refs
alert(input1.value)
}
//展示右侧输入框的数据
showData2 = ()=>{
const {input2} = this.refs
alert(input2.value)
}
render(){
return(
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input ref="input2"
onBlur={this.showData2}
ref={c => this.input2 = c }
type="text"
placeholder="失去焦点提示数据"
/>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))
refs与事件处理:
1.通过onXxx属性指定事件处理函数(注意大小写)
1)React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
2)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
2.通过event.target得到发生事件的DOM元素对象
三,组件的生命周期
在React16之前的旧生命周期:
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
1. constructor()//构造器
2. componentWillMount()//组件将要挂载的钩子
3. render() =====> 必须使用的一个
4. componentDidMount() =====> 常用//组件挂载完毕的钩子
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
2. 更新阶段: 由组件内部this.setSate()或父组件render触发
1. shouldComponentUpdate()//控制组件更新的“阀门”,静态的,return true 或者false,默认返回true
2. componentWillUpdate()//组件将要更新的钩子
3. render() =====> 必须使用的一个
4. componentDidUpdate()//组件更新完毕的钩子
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
1. componentWillUnmount() =====> 常用//组件将要卸载的钩子
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
其旧生命周期图示如下:
在React16之后的新生命周期:
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
1. constructor()//构造器
2. static getDerivedStateFromProps()
//得到一个state的衍生(派生)状态,state的值在任何时候都取决于props
//且必须返回state object或者null
3. render()
4. componentDidMount() =====> 常用//组件挂载完毕的钩子
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
1. static getDerivedStateFromProps()
//得到一个state的衍生(派生)状态,state的值在任何时候都取决于props
//且必须返回state object或者null
2. shouldComponentUpdate()//控制组件更新的“阀门”,静态的,return true 或者false,默认返回true
3. render()
4. getSnapshotBeforeUpdate()//在更新之前获取快照
5. componentDidUpdate()//组件更新完毕的钩子
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
1. componentWillUnmount() =====> 常用//组件将要卸载的钩子
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
其新生命周期图示如下:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。