React快速暴力入门(二)
1.组件的三大属性
组件的实质就是个对象,而对象自然有属性,在组件里最常用的三个属性分别是 state、props和 refs(上期呢我们已经讲过state了 有需要的可以去上一个博客看哦)
1. props
与 state不同,state是组件自身的状态(数据),而 props则是外部传入给自己的状态(数据)
props在组件内修改,必须由谁传入的即由谁修改
类式组件中使用
class Person extends React.component{
constructor(props){ // 还记得构造函数的参数吗,也能够获取 props
super(props);
}
// 可以使用静态属性 propTyps 来限制props
static propTypes = {
// 在 16版本前,通过使用React自带的PropTypess属性传递值
// name: React.PropTypes.string.isRequired,
// 16版本后,PropTypes被单独移出 React作为单独的个体,需要另外导入
name: PropTypes.string.isRequired, // 字符串类型,且必须传值
sex: PropTypes.string, // 字符串类型
age: PropTypes.number, // 数字类型
speak: PropTypes.func, // 函数类型
}
// 可以使用静态属性 defaultProps 来设置某些 prop 的默认值
static defaultProps = {
sex: "男", // 设置 sex 的 prop 默认值为 “男”
}
render(){
const {name, sex, age} = this.props; // 从 props中获取值
return (
<ul>
<li>姓名:{name}}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
// ReactDOM.render( <Person name="Tom" sex="男" age="16"/>, document.querySelector("#root")); // 以类似属性的方式传递 props值
ReactDOM.render(<Person {...p} />, document.querySelector("#root"));
// 可以用扩展运算符来传递 props值
在使用的时候可以通过 this.props来获取值 类式组件的 props:
- 通过在组件标签上传递值,在组件中就可以获取到所传递的值
- 在构造函数的参数里可以获取到 props
- 可以分别设置 propTypes 和 defaultProps 两个属性来分别操作 props的规范和默认值,两者都是直接添加在类式组件的原型对象上的(所以需要添加 static)
函数式组件中使用
还记得说函数式组件的参数是什么吗?便是 props。
传入的方式与类式组件相同,都是在组件标签中传递值
function Person(props){ // 参数为 props
const {name, sex, age} = props; // 使用占位符获取 props的值
return (
<ul>
<li>姓名:{name}}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
Person.defaultProps = { // 设置 props默认值
sex: "男",
age: 18,
}
Person.propTypes = { // 设置 props限制
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
}
const p = {name:"Jerry", sex:"女", age:16}
ReactDOM.render(<Person {...p}/>,document.querySelector("#app"));
函数组件的 props定义:
- 同样也是在组件标签中传递 props的值
- 组件函数的参数为 props
- 对 props的限制和设置默认值也同样实在原型对象上
2. refs
假设在你的组件里有着表单元素,然后你需要获取到其中的值,该怎么获取呢?有的人可能想给元素绑定 id后用 document.querySelector来查找元素,但这样就违背了 React的想法,又开始操作起了DOM元素,所有React提供了第三种特性 refs
在React的历史中,共有三种操作refs的方法,分别为:
- 字符串形式
- 回调形式
- createRef形式
让我们一一来了解一下:
类式组件中使用 refs
1)字符串形式的 refs
class Demo extends React.Component{
showData(){
// 通过自己设定的 refs名称获取对应的元素
const {myInput} = this.refs; // 返回该元素
alert(myInput.value)
}
render(){
return (
<div>
{ /* 通过 ref属性绑定这个 input标签 */ }
<input type="text" ref="myInput" placeholder="search something" />
{/* 事件绑定会在下面讲 */}
<button onClick={this.showData}>Show Data</button>
</div>
)
}
}
2). 回调形式的 refs
其实很简单,但在后来的版本中,官方觉得这样class Demo extends 做有问题,于是推出了全新的版本:使用回调函数来操作 refs
React.Component{
showData(){
const {myInput} = this; // 返回该元素
alert(myInput.value)
}
render(){
return (
<div>
{/* 回调函数的参数为该元素本身,通过函数绑定在 this上 */}
<input type="text" ref={ e => this.myInput = e } placeholder="search something" />
<button onClick={this.showData}>Show Data</button>
</div>
)
}
}
3). createRef形式(推荐)
后来的React发现,使用回调函数的形式还是会出现一些不可言喻的问题,所以,又一次推出了全新的的方法来使用 refs,便是使用 React身上的方法 createRef()
class Demo extends React.Component{
// 使用 React.createRef() 创建一个 ref容器
myRef = React.createRef();
showData = ()=>{
// 在容器中获取 DOM元素
const {current} = this.myRef;
alter(current.value);
}
render(){
return (
<div>
{/* 将DOM元素绑定在容器中 */}
<input ref={this.myRef} placeholder="点击提示数据" type="text"/>
<button onClick={this.showData}>ShowData</button>
</div>
)
}
}
注意:一个 ref容器,只能存储一个元素(专人专用),后加入的会把前一个顶出去
函数式组件中使用 refs
- 在React16.8前,与 state相同,函数式组件也无法使用 refs特性
- 在React16.8后,出现了 Hook函数,使得函数式组件也有了使用 refs特性的能力
以下代码现阶段无需看懂先,了解即可。
function Demo() {
const [count, setCount] = React.useState(0);
function add(){
setCount(count=> count+1);
}
return (
<div>
<h2>当前求和:{count}</h2>
<button onClick={add}>点击加一</button>
</div>
)
}
2.组件的事件绑定
1. 在函数式组件中进行事件绑定
可以在函数中定义另外一个函数(内置函数)然后进行调用即可
function Demo(props){
function showData(){
console.log(props);
alert("触发了事件");
}
return (
<div>
<button onClick={showData}>点击触发</button>
</div>
)
}
2. 在类式组件中进行事件绑定
在类式组件中可以通过类本身的方法来调用
class Demo extends React.Component{
state = { count: 0 } // 定义 state
showData(){
alert("触发了事件")
console.log(this.state.count);; 报错
}
render(){
return (
<div>
<button onClick={this.showData}></button>
</div>
)
// 成功弹出弹窗,但是输出报错
}
}
这里你会发现,虽然成功 alter,但是输出 state会报错,这是为什么呢?
平时在组件内使用 this.state的时候,此时 this的指向都是作用于类的原型对象,即类本身。
而在函数中,因为使用了 babel.js的缘故,js默认开启了严格模式,所以函数体的 this为 undefined,自然找不到在原型对象上的 state。
此时有两种解决方法:
- 使用 bind、apply等方法改变 this指向
- 使用箭头函数,改变 this指向(推荐)
class Demo extends React.Component{
constractor(props){
super(props);
// this.showData = this.showData.bind(this); // 方法1
}
state = { count: 0 } // 定义 state
showData = ()=>{ // 方法2
alert("触发了事件")
console.log(this.state.count);; 报错
}
render(){
return (
<div>
<button onClick={this.showData}></button>
</div>
)
// 成功弹出弹窗,但是输出报错
}
}
3.React的事件处理方法
通过 onXxx属性指定事件处理函数(注意大小写
React使用的是自定义(合成)事件,而不是原生的 DOM事件(为了更好的兼容性)
React的事件是通过事件委托方式处理的(委托给组件最外层的元素)(为了更加的高效)
可以通过事件的 event.target获取发生的DOM元素对象,可以尽量减少 refs的使用
在绑定事件的时候不要加括号,这会被 jsx识别为执行函数
在类式组件中绑定函数注意 this的指向问题(推荐绑定的函数都使用箭头函数)
3.组件的生命周期
对 Vue熟悉的应该对生命周期并不陌生。
组件在挂载到页面上的过程中,期间发生了许多的事情,而生命周期,可以看作是一个组件的执行流程,我们可以通过在某个流程节点中进行一些操作,而这就是 生命周期钩子(函数)
注:生命周期函数只适用于类式组件,并不适用于函数式组件,但是在React16.8之后的 Hook,也可以让函数式组件实现类似于生命周期钩子的功能
1.React 16之前
以下是流程:
自身组件挂载
- constructor: 构造函数(初始化)
- componentWillMount: 组件挂载前
- render: 组件挂载中
- componentDidMount: 组件挂载完成后
拥有父组件且父组件状态进行更新(setState):
- 父组件 shouldComponentUpdate: 父组件是否进行状态更新
- 父组件 componentWillUpdate: 父组件状态更新前
- 父组件 render: 父组件更新挂载中
- 子组件 componentWillReceiveProps: 子组件将收到新的Props
- 子组件 shouldComponentUpdate: 子组件是否进行状态更新
- 子组件 componentWillUpdate: 子组件状态更新前
- 子组件 render: 子组件更新挂载中
- 子组件 componentDidMount: 子组件挂载完成
- 父组件 componentDidMount: 父组件挂载完成
当组件要进行卸载时:
- componentWillUnmount: 组件卸载前
有几个需要注意的地方:
- shouldComponentUpdate的意思是是否更新状态,所以他应该有个布尔类型返回值,而且默认为 true(不写的时候),当你写了这个钩子时别忘了写个返回值,这个横眉周期一般用于进行更新值的一些判断。
- shouldComponentUpdate有两个参数,分别是 nextProps:新的props 与 nextState: 新的state,此时他们都还没更新到组件上。
- 使用 setState时会经过生命周期 shouldComponentUpdate,但是使用 forceUpdate时则不会,而是直接到 componentWillUpdate生命周期
2. React 16之后
新旧生命周期对比:
1.在新的生命周期中,舍弃了(即将舍弃)三个生命周期函数:
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
2.新增了两个生命周期函数:
- getDerivedStateFromProps
- getSnapshotBeforeUpdate
以下是流程:
- 自身组件挂载:
- constructor: 构造函数(初始化)
- getDerivedStateFromProps: 从props中获取派生的state
- render: 组件挂载中
- componentDidMount: 组件完成挂载
父组件更新时
- 父组件 getDerivedStateFromProps: 从 props中获取派生的state
- 父组件 shouldComponentUpdate: 判断是否进行状态更新
- 父组件 render: 父组件挂载中
- 子组件 getDerivedStateFromProps: 从 props中获取派生的state
- 子组件 shouldComponentUpdate: 判断是否进行状态更新
- 子组件 render: 子组件挂载中
- 子组件 getSnapshotBeforeUpdate: 子组件获取状态更新前的快照
- 子组件 componentDidUpdate: 子组件完成更新
- 父组件 getSnapshotBeforeUpdate: 父组件获取状态更新前的快照
- 父组件 componentDidUpdate: 父组件完成更新
组件卸载时
- componentWillUnmount: 组件卸载前
也有几个需要注意的地方:
- getDerivedStateFromProps 需要定义个实例本身,所以是静态方法
- getDerivedStateFromProps 有两个参数,分别是当前的 props和 state
- 若需要组件的状态任何时候都取决于 props则可以使用 则可以使用 getDerivedStateFromProps,但是使用场景比较罕见,可以在其中定义 state
- getSnapshotBeforeUpdate 有两个参数,分别为状态更新前的 props 和state,并且有一个返回值(快照),一般用作本次更新情况的说明情况。
- componentDidUpdate 有三个参数,分别为状态更新前的 props 和 state,以及先前 getSnapshotBeforeUpdate返回的快照。
- 其他的与旧的生命周期没有什么差别
4.总结
相信你也看完了整个了,我们今天讲了属性 生命周期 事件绑定等等 哪在本文中呢 我也在该注意的地方写了要注意什么 如果本文还有什么有不懂的 也可以看官网哦