组件和组件属性
组件:包含内容、样式和功能的UI单元
创建一个组件
特别注意:组件的名称首字母必须大写
用域区分组件还是单个普通的react元素不再是函数ttype
- 函数组件
返回一个React元素
分析 首先分为当页js 或者组件js 特别的组件js也要引入react 因为要建立react 元素
其次 渲染函数接受时候两种方式 函数执行状态 组件标签状态 如下
组件返回值仍是一个react元素 变化的只是type值
function MyCom1() {
return <li>我的组件1</li>
}
console.log(api.MyCom)
let MyCom = api.MyCom;
ReactDOM.render(<div>
<MyCom></MyCom>
<MyCom1></MyCom1>
</div>, conter);
//组件内容
import React from 'react';
import ReactDOM from 'react-dom';
let api = {};
api.MyCom = function() {
// eslint-disable-next-line react/react-in-jsx-scope
return <div>我的组件</div>
}
// eslint-disable-next-line no-unused-expressions
export default api;
- 类组件
必须继承React.Component
必须提供render函数,用于渲染组件 入口文件每次使用组件都会创建一个react 元素 type为类类型
//组件内容
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
export default class MyClassCom extends Component {
render() {
return (
<div>
<li>这是类组件元素</li>
</div>
)
}
}
//入口文件渲染
import MyClassCom from'./MyClassCom'
ReactDOM.render(<div>
<MyCom></MyCom>
<MyClassCom></MyClassCom>
</div>, conter);
组件的属性
自定义组件传值可以利用属性传html结构代码 映射到react中 是一个对象
也可以和html一样直接写
传递元素内容
内置组件:div、h1、p
<div>
asdfafasfafasdfasdf
</div>
props.children
props.content1 ...... 可以同时将属性和自定义元素传递进去props里面
如果给自定义组件传递元素内容,则React会将元素内容作为children属性传递过去。 会忽略空白
- 对于函数组件,属性会作为一个对象的属性,传递给函数的参数
import React from 'react' export default function student(props) { console.log(props); return ( <div> <li> 【姓名】:{props.name} 【性别】:{props.sex === 0 ? '男' : '女'} 【Email】:{props.email} 【地址】:{props.address} </li> </div> ) }
- 对于类组件,属性会作为一个对象的属性,传递给构造函数的参数
-
import React, { Component } from 'react' import Student from './Student' export default class StudentLIst extends Component { render() { console.log( this.props.data) // eslint-disable-next-line array-callback-return var list = this.props.data.map(item => { // eslint-disable-next-line no-unused-expressions return <Student {...item}></Student> }) console.log(list) return ( <ul> {list} </ul> ) } }
注意:组件的属性,应该使用小驼峰命名法
组件无法改变自身的属性。
之前学习的React元素,本质上,就是一个组件(内置组件)
React中的哲学:数据属于谁,谁才有权力改动
React中的数据,自顶而下流动
--------------------------------------------------------------------------------------------------------------------------
组件状态
组件状态:组件可以自行维护的数据
组件状态仅在类组件中有效
状态(state),本质上是类组件的一个属性,是一个对象 可以有我们自己控制 供自己使用
状态初始化
初始化要用构造函数初始化
//初始化组件状态
constructor(props) {
super(props);
console.log(props)
this.state = {
left:this.props.left || 0,
top:this.props.top || 0,
xSpeed:this.props.xSpeed || 0,
ySpeed:this.props.ySpeed || 0,
bg:props.bg || "#f40"
}
}
// 必须要用该函数改变state中的数据 才会触发重新渲染
this.setState({
left:newLeft,
top:newTop
})
// console.log(this.state)
状态的变化
不能直接改变状态:因为React无法监控到状态发生了变化 会导致其他引用该数据的地方出错
必须使用this.setState({})改变状态
一旦调用了this.setState,会导致当前组件重新渲染 自动触发重新渲染
组件中的数据
- props:该数据是由组件的使用者传递的数据,所有权不属于组件自身,因此组件无法改变该数组
- 传来的数据不可以改变
- state:该数组是由组件自身创建的,所有权属于组件自身,因此组件有权改变该数据 但是改变自己组件的数据依然会影响自己组件的子组件
-----------------------------------------------------------------------------------------
深入认识setState
setState,它对状态的改变,可能是异步的
注意 该setStatus()方法来讲 状态以改变完成之后立马调用render函数 所以render先于数字打印执行 针对回调函数而言
如果改变状态的代码处于某个HTML元素的事件中,则其是异步的,否则是同步
import React, { Component } from 'react'
export default class Test extends Component {
state = {
n : 1
}
handleChange = () => {
//改变组件属性 虽然写了多个语句但效果还是一部效果
// 不可以实现状态的连续改便
//此处我们想要做到同步改变 但是该方法是异步执行在第二个状态改变时 第一个状态改变尚未完成 故相当于只进行了一次状态改变
this.setState({
n:this.state.n + 1
})
this.setState({
n:this.state.n + 1
})
this.setState({
n:this.state.n + 1
})
console.log(this.state.n)
//此时获取到的是状态改变之前的值 0 获取状态改变后的值要用回调函数形式进行
//但是回调函数仍然无法做到连续改变 需要用回调中嵌套回调才可以
}
render() {
console.log('render')
return (
<div>
<span>{this.state.n}</span>
<button onClick={this.handleChange}>+</button>
</div>
)
}
}
如果遇到某个事件中,需要同步调用多次,需要使用函数的方式得到最新状态 代码如下
import React, { Component } from 'react'
export default class Test extends Component {
state = {
n : 1
}
handleChange = () => {
//改变组件属性 虽然写了多个语句但效果还是一部效果
// 不可以实现状态的连续改变
// 改用一下回调函数形式就可实现同步操作 它本质上是异步的
this.setState({
n:this.state.n + 1
},() =>{
// 注意:
// 1、该函数在状态改变完成之后调用 该回调函数运行于render之后
// 今后凡是获取改变后的状态均要使用回调函数形式进行
console.log(this.state.n)
})
}
render() {
console.log('render')
return (
<div>
<span>{this.state.n}</span>
<button onClick={this.handleChange}>+</button>
</div>
)
}
}
最佳实践:
- 把所有的setState当作是异步
- 永远不要信任setState调用之后的状态 因为它是异步的有可能状态还没有改变
- 如果要使用改变之后的状态,需要使用回调函数(setState的第二个参数)
- 如果新的状态要根据之前的状态进行运算,使用函数的方式改变状态(setState的第一个函数)
React会对异步的setState进行优化,将多次setState进行合并(将多次状态改变完成后,再统一对state进行改变,然后触发render)