一、构建项目
脚手架:自动一个大型项目的目录 但不能直接运行 还需要脚手架进行编译
React官方提供一个脚手架工具:
把上次访问的网页存储在浏览器里
二、React基本使用
在子组件中 解构赋值:
在index.js中 使用ReactDOM把APP 组件 挂载到 id=root 的DOM节点上
是一个JSX语法 为了正常运行JSX语法 必须引入React 必须
JSX语法:
可以使用HTML5标签
也可以使用自己组件的自定义标签 不用再标签外面包裹单引号' '
如果要使用自己创建的组件 可以通过自定义的标签(开头必须大写)<App />
使用React编写todoList功能
首先创建这个组件
在render函数里,return回来的内容在最外层必须包裹一个标签 如:
如果想要在外面包裹一层 又不想显示出来 可以使用占位符Fragment
引入,使用Fragment替代div 既能包裹 又不显示 真好
React中的响应式设计思想和事件绑定
不是直接操作DOM 而是操作数据 不用关注DOM操作
React要把数据定义在状态state里
并且可以调用这些数据 在JXS中使用JS表达式要加上{ }
React可以感应数据的变化,并且响应
可是此时input框的值没法改变,被写死为inputValue 成了个单向绑定 如果想要双向绑定 就需要绑定onChange事件 并执行对应的事件处理程序
e.target:input框对应的DOM节点
但此时有一个问题:
这个时候this的指向undifined 为了让this指向该组件,需要进行绑定(这个思路需要牢记 )
想改变State里面的数据,需要使用setState方法:
1.用state存储组件数据
2.JSX里使用JS表达式 需要 { }
3.事件绑定里需要bind改变指向作用域
4.改变state数据需要setState( )函数来改变
实现列表新增功能,通过改变list数据内容:
实现删除功能
要注意两点
1.利用bind可以往回调函数里传递一些参数
2.修改state时要拷贝出来一个副本 修改这个副本 而不能直接修改state
JSX细节语法:
1.写注释
2.增加样式
单独创建一个.css文件 并在.js文件里引入 但此时使用的类选择器 class 会报错
需要改为:
3.不对标签进行转义 直接按照<h1>的格式显示内容
4.label 扩大点击范围 但此时for也会报错 需要写成htmlFor
组件拆分与组件传值
在父组件中使用子组件 通过JSX语法
父组件向子组件传值,是通过属性的方式传递:
子组件通过props得到数据:
子组件调用父组件方法,修改父组件的值:
其实就是把父组件的方法传给子组件 子组件就可以调用这个方法了
注意:要用bind改变指向,将this绑定
在子组件中调用该方法,同样也需要bind绑定:
但为了提高性能,在constructor里进行bind绑定
代码优化
1.利用解构赋值美化代码
2.setState可以写成函数形式
也可以写成 还需要把target.value保存在外层
prevState 代表之前的数据 可以直接使用
对React的思考:
React是声明式的开发 而jQuery则是命令式的开发
React只是一个视图层的框架,而不是大型完整的框架,只做页面上的一些渲染
React里 父组件可以给子组件传值 但是子组件不能修改值 这就是单向数据流 所以子组件只能通过调用父组件的方法来修改数据 本质上还是父组件在修改数据
三、Reacgt高级内容
PropTypes DefaultProps
PropTypes 对父组件传来的属性做校验 规定类型 不能乱穿
如果不传 就不会校验
可以强制必须要传
DefaultProps 默认值
props State render(原理)
当组件的state 或 props 发生改变的时候 render就会重新执行
当父组件的render函数重新执行时,它的子组件中的render也会跟着重新运行
React中的虚拟DOM
真实DOM的思路:
但存在缺陷:生成太多次完整DOM 耗费性能
改进思路:
但性能提升并不明显
而在React中,使用虚拟DOM:
所以,整体思路是:
J
下图就是一个JSX模板:
下图 方法1:JSX模板 方法2:createElement方法
Diff算法:
两个虚拟DOM比对的方式:Diff算法
Diff进行同层比对 比较出不同后 就把下面的重新替换掉:
循环中需要key值 将新旧值对应起来 如果没有key值比对会麻烦,
但要求原始和新的key值一致 所以不建议使用index作为key值 应该使用更为稳定的值作为key值
React中的ref
ref是一个引用,使用ref来操作DOM
可以使用e.target获取DOM节点 也可以使用ref获得DOM节点
在React中 ref 是一个函数 this.input指向此时的input标签对应的DOM元素
可用用this.input来替换e.target
但并不推荐使用ref
因为setState是一个异步函数,如下代码,console.log可能在setState之前执行,因此获得的DOM结果可能出错
如果想要在页面更新完成后获取DOM 则需要把console写在setState的第二个函数里:
生命周期函数
生命周期函数指某一个时刻组件自动执行调用的函数
render就是一个生命周期函数,在数据发生变化时自动执行
Initialization:页面初始化
Mounting:第一次挂载时
componentWillMount:组件即将被挂栽到页面上时执行
componentDidMount:组件被挂在到页面之后被执行
Updation:组件被更新时
props或states
shouldComponentUpdate:组件被更新之前自动执行 返回一个布朗值 返回true 页面将会更新 返回false 就不更新
componentWillUpdate:组件被更新之前,会自动执行,但在shouldComponentUpdate返回true之后才被执行
componentDidUpdate:组件更新之后,会被执行
特殊的componentWillReceiveProps:
当一个组件从父组件接受了参数,只要父组件的render函数被重新执行,子组件的componentWillReceiveProps就会执行
如果这个组件第一次存在于父组件中,不会执行
如果这个组件之前就已经存在于父组件中了,才会被执行
Unmounting:把组件从页面上去除
componentWillUnmount:当这个组件即将从页面上剔除的时候,执行
生命周期函数是针对组件而言的,每个组件都有自己的生命周期函数
生命周期函数使用场景:
由于父组件render执行时,子组件也会重新渲染,造成了浪费,可以使用生命周期函数进行优化:
在子组件里:
React请求AJAX
把AJAX放在componentDidMount (因为该函数只被执行一次)但React本身没有封装AJAX请求模块 需要使用扩展工具 npm add axios
并且引入
使用Charles实现本地数据mock
模拟接口数据:
1.创建文件 todolist.json
2.在json里写个数组
3.使用Charles配置 当向外发送请求时 把本地的数据返回回去
4.将返回的数据挂载上
react-transition-group动画框架
是个第三方模块 需要添加