声明式的开发 React
命令式的开发 Jquery
单项数据流
父组件可以给子组件传值,但子组建不能改变这个值
单项数据流的好处:
实际是为了开发时方便,不容易遇到坑,方便测试。
一个父子建有五个子组件,假如没有单项数据六的概念,任何一个子组件把父组件给改变了(删除等),其余的几个组建也会受到影响。
视图层框架
数据层框架
函数式编程
TodoList.js中的文件
import React, { Component,Fragment } from 'react';
import './style.css'
import TodoItem from './TodoItem';
import Test from './Test';
// import { Component } from 'react';
// import React from 'react'
// const Component = React.Component
// Fragment 代替div
class TodoList extends Component {
constructor(props){
super(props); //继承
// 组建的状态
this.state = {
inputValue: '',
list: ['1','2'],
}
this.handleInputChange = this.handleInputChange.bind(this)
}
//在组件即将被挂载在页面的时刻自动执行
componentWillMount(){
console.log('componentWillMount')
}
render() {
return (
<Fragment>
<div>
{/*下面时一个input框*/}
{
//下面时一个input框
}
<label htmlFor="insertArea">输入内容</label>
<input
id='insertArea'
className='input'
value={this.state.inputValue} type=""
onChange={this.handleInputChange}
ref={(input) => {this.input = input}}
/>
<button onClick={this.handleBtnClick.bind(this)}>提交</button>
</div>
<ul ref={(ul) => {this.ul=ul}}>
{ this.getTodoItem() }
</ul>
<Test content={ this.state.inputValue } />
</Fragment>
);
}
//在组件挂载在页面的完毕时刻自动执行
componentDidMount(){
console.log('componentDidMount')
}
//组件更新之前,他会自动被执行==你的组件需要被更新?决定组件是否要被更新
shouldComponentUpdate(){
console.log('shouldComponentUpdate')
return true
}
//组件被更新之前,他会自动执行,但是他在shouldComponent之后被执行,、
//如果shouldComponentUpdate返回true才执行
//如果shouldComponentUpdate返回false不执行
componentWillUpdate(){
console.log('componentWillUpdate')
}
//组件更新完成之后会被执行
componentDidUpdate(){
console.log("componentDidUpdate")
}
getTodoItem() {
return this.state.list.map((item,index)=>{
return (
<div key={index}>
<TodoItem
content={item}
index={index}
deleteItem = {this.handleItemDelete.bind(this)}
/>
{/*<li
key={index}
onClick={this.handleItemDelete.bind(this,index)}
dangerouslySetInnerHTML={{ __html:item }}
>
</li>*/}
</div>
)
})
}
handleInputChange(e){
console.log(this.input.value)
//react最新版本的改变状态的写法
const value = e.target.value
this.setState( () => ({
inputValue: value
}))
// this.setState({
// inputValue: e.target.value
// })
}
handleBtnClick(){
// 异步
this.setState( (prevState) => ({
// prevState之前的数据
list: [...prevState.list,prevState.inputValue],
inputValue: ''
}),() => {
console.log(this.ul.querySelectorAll('div').length)
})
// console.log(this.ul.querySelectorAll('div').length)
// this.setState({
// list: [...this.state.list,this.state.inputValue],
// inputValue: ''
// })
}
handleItemDelete(index){
// immutable
// state 不允许我们做任何改变
// const list = [...this.state.list]
this.setState((prevState)=>{
const list = [...prevState.list];
list.splice(index,1)
return {list}
})
// this.setState({
// list: list
// })
}
}
export default TodoList;
TodoItem.js
import React,{ Component } from 'react';
import PropTypes from 'prop-types';
class TodoItem extends Component{
constructor(props){
super(props)
this.handleClick = this.handleClick.bind(this)
}
// 使用 shouldComponentUpdate优化性能,不需要input输入值改变就重新渲染子组件,做个判断
shouldComponentUpdate(nextprevProps,nextState){
console.log(nextprevProps,nextState)
if(nextprevProps.conent !== this.props.conent){
return true
}else{
return false
}
}
render(){
const { content, test } = this.props
return (
<div
key={this.props.index}
onClick={this.handleClick}
>
{/*React.createElement('div',{},'item')*/}
{ test } - { content }
</div>
)
}
//当一个组件从父组件接收了参数
//只要父组件的render函数执行了,子组件的这个生命周期函数就会被执行
//如果这个组件第一年存在于父组件中,不会执行
//如果这个组件之前已经存在于父组件中,会被执行
componentWillReceiveProps(){
console.log("child componentWillReceiveProps")
}
//当这个组件即将被从页面剔除的时候,会被执行
componentWillUnmount(){
console.log("child componentWillUnmount")
}
handleClick(){
const { deleteItem,index } = this.props
deleteItem(index)
}
}
//属性校验==要求父组件给子组件传值的校验
// isRequired 必须要传值
TodoItem.propTypes = {
test: PropTypes.string.isRequired,
content: PropTypes.oneOfType([PropTypes.string,PropTypes.number]),
deleteItem: PropTypes.func,
index: PropTypes.number,
}
TodoItem.defaultProps = {
test: 'hello world'
}
export default TodoItem
Test.js
import React,{ Component } from 'react';
class Test extends Component{
render () {
return <div>{ this.props.content }</div>
}
}
export default Test
propTypes 与 DefaultProps
//属性校验==要求父组件给子组件传值的校验
TodoItem.propTypes = {
content: PropTypes.string,
deleteItem: PropTypes.func,
index: PropTypes.number
}
// 默认复制
TodoItem.defaultProps = {
test: 'hello world'
}
Props,State与render函数
当数据发生变化时,页面就跟着发生变化
当组件的state或者props发生改变的时候,render函数就会重新执行;
当父组件的render函数被运行时 ,他的子组件的render都将被重新运行一次
什么是虚拟DOM?
原始操作的方法
1. state 数据
2. jsx 模板
3. 数据 + 模板 结合,生成真是的DOM,来显示
4. state 发生改变
5. 数据 + 模板 结合,生成真是的DOM,替换原始的DOM
缺陷:
第一次生成了一个完成额DOM片段
第二次又生成了一个完成的DOM片段
第二次的DOM替换第一次的DOM,非常好性能
1. state 数据
2. jsx 模板
3. 数据 + 模板 结合,生成真是的DOM,来显示
4. state 发生改变
5. 数据 + 模板 结合,生成真是的DOM,并不直接替换原始的DOM
6. 新的DOM和原始的DOM作比对,找差异
7. 找出input框发生了变化
8. 只用新的DOM中的input元素,替换掉老的DOM中的input元素
缺陷:
性能的提升并不明显
React引入的虚拟DOM提高性能的方式
1. state 数据
2. jsx 模板
3. 数据 + 模板 生成虚拟DOM(虚拟DOM就是一个js对象,用它来描述真是的DOM)(损耗了性能)
['div',{id:'abc'},['span',{},"hello world"]]
4. 用虚拟dom的结构生成真是的DOM,来显示
<div id="abc"><span>hello world</span></div>
5. state 发生变化
<div id="abc"><span>bye bye</span></div>
6. 数据+模板 生成虚拟DOM(极大的提升了性能)
['div',{id:'abc'},['span',{},"bye bye"]]
7. 比较原始虚拟DOM和新的虚拟DOM的区别,找到区别是span中的内容(极大的提升了性能)
diff
setState 异步算法,提高了比对。
8. 直接操作DOM,改变span中的内容
有点:
1.性能提升了
2.他使得跨端应用得以实现。 React Native
//深入了解虚拟DOM
//虚拟DOM中的DIff算法
//React 中的ref的使用
React中的生命周期函数
//生命周期函数指在某一时刻组件会自动执行的函数
//在组件即将被挂载在页面的时刻自动执行
componentWillMount(){
console.log('componentWillMount')
}
//在组件挂载在页面的完毕时刻自动执行
componentDidMount(){
console.log('componentDidMount')
}
//组件更新之前,他会自动被执行==你的组件需要被更新?
shouldComponentUpdate(){
console.log('shouldComponentUpdate')
return true
}
//组件被更新之前,他会自动执行,但是他在shouldComponent之后被执行,、
//如果shouldComponentUpdate返回true才执行
//如果shouldComponentUpdate返回false不执行
componentWillUpdate(){
console.log('componentWillUpdate')
}
//组件更新完成之后会被执行
componentDidUpdate(){
console.log("componentDidUpdate")
}
//当一个组件从父组件接收了参数
//只要父组件的render函数执行了,子组件的这个生命周期函数就会被执行
//如果这个组件第一年存在于父组件中,不会执行
//如果这个组件之前已经存在于父组件中,会被执行
componentWillReceiveProps(){
console.log("child componentWillReceiveProps")
}
//当这个组件即将被从页面剔除的时候,会被执行
componentWillUnmount(){
console.log("child componentWillUnmount")
}