接上一条博客的内容,再次附上视频教程的学习地址
链接:https://www.bilibili.com/video/BV184411x7F9
上一篇文章链接:https://blog.csdn.net/AtalantaDavis/article/details/108244938
第二章 React面向组件编程
React测试示例的步骤
- 定义组件
//方式1:工厂函数组件(简单组件)
function MyComponent(){
return <h2>工厂函数组件(简单组件)</h2>
}
//方式2:ES6类组件(复杂组件)
class MyComponent2 extends React.Component {
render () {
return <h2>ES6类组件(复杂组件)</h2>
}
}
- 渲染组件标签
ReactDOM.render(<MyComponent />,document.getElementById('example1'))
ReactDOM.render(<MyComponent2 />,document.getElementById('example1'))
在组件类里面打印this,指向Mycomponent2标签
组件的三大属性
state
是个对象,俗称状态机,有状态不能用工厂模式
编码操作
- 初始化状态
constructor(props) { // 固定写法
super(props) // 调用,将props传给父类型
// 初始化状态
this.state = {
stateProp1:value1,
stateProp2:value2
}
}
- 读取某个状态值
this.state.stateProp1=value2
- 更新状态
this.setState()
示例步骤
- 定义组件
class Like extends React.component{
constructor(props) { // 固定写法
super(props) // 调用,将props传给父类型
// 初始化状态
this.state = {
isLike: false
}
// 将新增的方法中的this强制绑定为组件对象
this.handleClick = this.handleClick.bind(this)
}
// 新添加方法:内部的this默认不是组件对象,而是undefined
handleClick () {
// 得到状态
const isLike =!this.state.isLike
this.setState({isLike})
}
// 重写组件类的方法
render(){
const {isLikeMe} = this.state
return <h2 onClick={this.handleClick}>{isLike?'你喜欢我':'我喜欢你'}</h2>
}
}
- 渲染组件标签
ReactDOM.render(<Like />,document.getElementById('example1'))
props
对象
编码操作
- 对props中的属性值进行类型限制和必要性限制,引入prop-type.js
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number
}
- 指定属性默认值
Person.defaultProps = {
sex: '男',
age: 18
}
- 标签简写
ReactDOM.render(<Person {...p1} /> ,document.getElementById('example1'))
...
的作用:1.打包 ;2.解包
示例步骤
- 定义组件
function Person(props) {
return (
<ul>
<li>姓名:{props.name}</li>
<li>年龄:{props.age}</li>
<li>性别:{props.sex}</li>
</ul>
)
}
- 渲染组件标签
const p1 = {
name: 'Tom',
age: 18,
sex: '女'
}
ReactDOM.render(<Person name={p1.name} age={p1.age} sex={p1.sex} />,document.getElementById('example'))
refs
示例步骤
- 定义组件
class myComponent extends React.componenet {
constructor(props) {
super(props)
this.showInput = this.showInput.bind(this)
this.handleBlur = this.handleBlur.bind(this)
}
showInput() {
const input = this.refs.content
alert(this.input.value)
}
handleBlur(event){
alert(event.target)
}
render() {
return (
<div>
<input type="text" ref="content"/>
<input type="text" ref={input => this.input = input}/>
<button onClick={this.showInput]>提示输入</button>
<input type="text" placeholder="失去焦点提示内容" onBlur={this.handleBlur}>
</div>
)
}
}
- 渲染组件标签
ReactDOM.render(<MyComponent />,document.getElementById('example'))
三种特点总结
state 数据从组件内部传来
props 数据从组件外部传来
refs
组件化编码流程
- 拆分组件:拆分界面,抽取组件
- 实现静态组件:使用组件实现静态页面效果
- 实现动态组件
- 动态显示初始化数据
- 交互功能
示例
// 1. 定义组件
// 问题:数据保存在哪个组件里// 看数据是某个组件需要(给他),还是某些组件需要(给共同的父组件)
// 问题2:需要在子组件中改变负组件的状态
// 子组件中不能直接改变父组件的状态
// 状态在哪个组件,更新状态的行为就应该定义在那个组件// 解决:父组件定义函数,传递给子组件,子组件调用
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
todos:["111","222","22","333"]
}
this.addTodo = this.addTodo.bind(this)
}
addTodo (todo) {
const {todos} = this.state
todos.unshift(todo)
// 更新状态
this.setState({todos})
}
render () {
const {todos} = this.state
return (
<div>
<h1>Simple ToDo List</h1>
<Add count={todos.length} addTodo={this.addTodo} />
<List todos={todos}/>
</div>
)
}
}
class Add extends React.Component {
static propTypes = {
count: PropTypes.Number
}
constructor(props) {
super(props);
this.AddMessage = this.AddMessage.bind(this)
}
AddMessage () {
// 1.读取输入的数据
const todo = this.todoInput.value.trim()
// 2.检查合法性
if(!todo){
return;
}
// 3.添加
this.props.addTodo(todo)
// 4.清除输入
this.todoInput.value = ""
}
render () {
return (
<div>
<input type="text" ref={input=> this.todoInput = input}/>
<button onClick={this.AddMessage}>add #{this.props.count + 1}
</button>
</div>
)
}
}
class List extends React.Component {
static propTypes = {
todos: PropTypes.array,
addTodo: PropTypes.func
}
render () {
return (
<ul>
{this.props.todos.map((todo, index) => <li key={index}>{todo}</li>)}
</ul>
)
}
}
// 2. 渲染UI
ReactDOM.render(<App />, document.getElementById("example"))
组件提交提交表单数据
两种方式获取表单数据
受控组件:表单项输入数据能自动收集成状态,如示例中密码的获取方式,用state,根据react思想更支持受控组件
非受控组件:需要手动读取表单数据,如示例中用户名的获取方式,用refs,更轻松
示例编码
/*
* 自定义包含表单的组件
* 1. 界面如下所示
* 2. 输入用户名密码后,点击登录提示输入信息
* 3,不提交表单
* */
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
pwd: ''
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleSubmit (event) {
const name = this.nameInput.value
const {pwd} = this.state
alert(`准备提交的用户名${name},密码为${pwd}`)
//阻止事件的默认提交
event.preventDefault()
}
handleChange (event) {
// 读取输入的值
const pwd = event.target.value
// 更新pwd的状态
this.setState({pwd})
}
render() {
return (
<form action="/test" onSubmit={this.handleSubmit}>
用户名:<input type="text" ref={input => this.nameInput = input} />
密码:<input type="password" value={this.state.pwd} onChange={this.handleChange} />
<input type="submit" value="登录" />
</form>
)
}
}
ReactDOM.render(<LoginForm />, document.getElementById("example"))
组件的生命周期
生命周期函数
渲染过程
回调函数小知识
虚拟DOM挂在到真实容器上的过程叫挂载
回调函数:我定义的但是我没调用,但是它执行了
命令式编程:每一步都要自己写
生命周期流程
- 第一次初始化渲染显示:ReactDOM.render()
constructor():创建对象初始化state
componentWillMount():将要插入回调
render():用于插入虚拟DOM回调
componentDidMount():已经插入回调
- 每次更新state:this.setState()
componentWillUpdate():将要更新回调
render():更新(重新渲染
componentDidUpdate():已经更新回调
componentDidMount():已经插入回调,插入完成后运行
- 移除组件:ReactDOM.unmountComponentAtNode(containerDom)
componentWillUnmount():组件将要被移除回调
重要的勾子
render():初始化渲染或更新渲染调用
componentDidMount():开启监听,发送ajax请求
componentWillUnmount():做一些收尾工作,如:清理定时器
componentWillReceiveProps():当props发生改变时,会执行此操作,旧的props还可以通过this.props来获取。
示例编码
class Life extends React.Component {
constructor(props) {
super(props);
// 初始化状态
this.state = {
opacity: 1
}
this.distroyComponent = this.distroyComponent.bind(this)
}
componentDidMount () { //生命周期,挂载完成之前加载的函数
this.intervalId = setInterval(function() {
console.log("定时器执行....")
let {opacity} = this.state
opacity -= 0.1
if(opacity<=0){
opacity = 1
}
this.setState({opacity})
}.bind(this), 100)
}
distroyComponent () {
// 此生命周期用来卸载组件所在的DOM元素
ReactDOM.unmountComponentAtNode(document.getElementById("example"))
}
componentWillUnmount () {
// 此生命周期:在卸载挂载的DOM元素之前,运行的函数
// 清理定时器,如果不清理定时器,在卸载挂载之后还会继续定时
clearInterval(this.intervalId)
}
render (){
const {opacity} = this.state
return (
<div>
<h2 style={{opacity:opacity}}>{this.props.msg}</h2>
<button onClick={this.distroyComponent}>不活了</button>
</div>
)
}
}
ReactDOM.render(<Life msg="react太难了!"/>,document.getElementById("example"))
虚拟DOM与DOM Diff算法
初始化过程
下一篇文章链接:https://blog.csdn.net/AtalantaDavis/article/details/108342941