刚开始
定义一个组件
1 | import React, { Component, Fragment } form 'react' |
创建一个组件
1 | class TodoList extends Component { |
使用 Fragment 替代最外层的 <div>
使得最外层标签隐藏
React 设计思想和事件绑定
state 里面存储组件中使用的数据
JSX 中如果想使用 JS 表达式,需要使用{}包裹
事件绑定的时候需要使用 bind 对函数 this 指向进行变更
如果想改变数据项的内容,不能直接去改它,需要通过 setState 函数,通过传入一个对象的形式来对 state 进行更新
1 | constructor (props) { |
1 | handleChange (e) { |
列表渲染
1 | <ul> |
操作数组
1 | // 添加 |
冷门小知识
JSX 中 使用样式的
class
时不要使用class
应该使用className
当你想在页面中展示未转义的 html 内容使用
1
dangerouslySetInnerHTML={{__html: item}}
这种的未转义会造成 XSS 攻击 慎用!
在
<label>
标签上使用for
时,应使用htmlFor
父子传值
父传子
1 | // Parent |
子传父
1 | // Children |
代码优化
- 在 constructor 中进行 this 绑定
- 通过解构赋值的方式提取 props state 的值
- JSX 部分不要出现逻辑代码,如果出现建议拆分出来成为一个函数
- setState 时使用函数返回的方式修改
1 | const value = e.target.value |
React 思考
声明式开发
可以与其他框架一起开发
组件化
单向数据流
视图层框架
函数式编程
继续冲
PropTypes
类型校验
在子组件中通过 Children.propTypes = {}
的形式来声明 props 传过来的类型
1 | TodoItem.propTypes = { |
DefaultProps
定义默认值
在子组件中通过 Children.defaultProps = {}
的形式来设置默认值,当父组件没有向子组件传值的情况下会使用默认值
1 | TodoItem.defaultProps = { |
Props,State 与 render 函数关系
当组件的 state 或者 props 发生改变的时候,render 函数就会重新执行
- 在页面初始化的时候,render 函数会自动的执行一次
- State 发生改变,render 再次执行
- 当父组件的 render 运行时,它的子组件的 render 都将被重新运行一次
- 因为 props 改变了
- 因为父组件的 render 重新执行了
父组件 render -> 子组件 render
什么是虚拟 DOM
- State 数据
- JSX 模板
- 数据 + 模板 结合,生成真实 DOM,来显示
- State 发生改变
- 数据 + 模板 结合,生成真实 DOM,替换原始的 DOM
- 缺陷:
- 第一次生成了完成的 DOM 片段
- 第二次生成了一个完成的 DOM 片段
- 第二次生成的 DOM 他替换第一次的 DOM,非常耗性能
- State 数据
- JSX 模板
- 数据 + 模板 结合,生成真实 DOM,来显示
- State 发生改变
- 数据 + 模板 结合,生成真实 DOM,并不直接替换原始的 DOM
- 新的 DOM 和原始的 DOM 作比对,找差异
- 找出
input
框发生的变化 - 只用新的 DOM 中的 input 元素,替换掉老的 DOM 中的
input
元素
- 缺陷:
- 性能提升并不明显
- State 数据
- JSX 模板
- 生成虚拟 DOM (虚拟 DOM 就是一个 JS 对象,用它来描述真实 DOM) [损耗了性能]
- 用虚拟 DOM 的结构生成真实 DOM,来显示
- State 发生变化
- 数据 + 模板 生成新的虚拟 DOM [极大的提升了性能]
- 比较两次的虚拟 DOM,找到区别 [极大的提升了性能]
- 直接操作 DOM,改变内容
- 减少了对真实 DOM 的创建,和真实 DOM 的对比,创建的和对比的都是 JS 对象
深入理解虚拟 DOM
JSX –> createElement –> JS 对象 –> 真实 DOM
- 好处
- 性能提升了
- 它使得跨端应用得以实现。
DIFF 算法
同级比较
- 会对 DOM 树进行同层比对,如果发现某一层改变,会将它子节点全部替换掉(不管子节点是否改变),替换成新的 DOM 节点,虽然这样会造成性能上的损耗,子节点未改变也会被替换,但是这样的算法实现起来比较简单,从算法的角度看性能上还是比较优的。
Key 值比对
React 的 ref 使用
可以通过 e.target
的方式获取到触发事件的那个 DOM 节点
可以通过ref
的方式获取 DOM
1 | ;<input |
1 | this.setState( |
生命周期函数
生命周期函数指在某一时刻自动调用执行的函数
父组件 render –> 子组件的 render
Initialization
初始化 props 和 stateMounting
componentWillMount
在组件即将被挂载到页面的时刻自动执行render
componentDidMount
在组件被挂载到页面的时刻自动执行
Updation
Props
componentWillReceiveProps
当一个组件从父组件接受了参数,只要父组件的 render 函数重新执行了,子组件的这个函数就会被执行
如果这个组件第一次存在于父组件中,这个函数不执行
如果这个组件之前已经存在于父组件中,才会执行
shouldComponentUpdate
- 组件被更新之前,他会自动执行,需要返回一个 Boolean,控制组件是否更新
componentWillUpdate
- 组件被更新之前,它会自动执行,但是他在 shouldComponentUpdate 之后执行,如果 shouldComponentUpdate 返回 true 它会执行,否则它将不执行
render
componentDidUpdate
- 组件更新完成之后,它会被执行
States
shouldComponentUpdate
- 组件被更新之前,他会自动执行,需要返回一个 Boolean,控制组件是否更新
componentWillUpdate
render
componentDidUpdate
Unmounting
componentWillUnmount
- 当这个组件即将被从页面剔除的时候会被执行
使用场景
通过 shouldComponentUpdate
控制子组件的 render
1 | shouldComponentUpdate (nextProps, nextState) { |
React Css 动画
可以使用 CSS 自己编写动画,通过控制切换类名的方式实现动画
Redux
就是将组件中用到的数据放到一个公用的区域去存储。
Redux = Reducer + Flux
Redux Flow
创建 store
1 | // index.js |
组件中使用 store
1 | // 获取 store |
组件中提交更新 store 数据
1 | handleInputChange (e) { |
整体的流程:通过创建 store 和 reducer 管理数据,组件中获取 store 数据,如果想更新数据,向 store 派发出一个 action,action 通过 dispatch 传递给 store,store 传给 reducer,reducer 接收后做一些处理再将新的 State 返回,store 接收到以后进行更新,store 收到更新,组件监听 store 改变后自己也进行改变。
通过 actionCreators 管理 action
1 | // actionTypes.js |
Redux 使用原则
- Store 是唯一的
- 只有 Store 能够改变自己的内容 (reducer 只是处理后将新的 state 返回而已,更新还是 store 自己更新)
- Reducer 必须是纯函数 (给定固定的输入,就一定会有固定的输出,而且不会有任何副作用)
Redux 中核心 API
- createStore 创建 store
- store.dispatch 向 store 派发 action
- store.getState 获取 store 中的所有数据内容
- store.subscribe 订阅 store 的改变,只要 store 发生改变,这个订阅的函数就会被执行,我们就可以获取到最新的 store 数据
Redux ++
普通组件
1 | class TodoList extends Component { |
UI 组件
负责页面的渲染,不关心逻辑怎么走。
容器组件
负责页面的逻辑,并不关心页面长什么样子。
父组件通过 props
向 UI 组件传递数据和事件,UI 组件的所有涉及到逻辑部分都通过事件派发出来,UI 组件内不做逻辑操作
无状态组件
当一个组件中只有一个 render 函数时,我们就可以用一个无状态组件定义这个组件
1 | const TodoListUI = (props) => { |
性能比较高,因为他只是一个函数,普通的组件,是一个 JS”类”,这个里边还有 React 的一些生命周期函数,和 render, 所要执行的东西较多。
当在做一个 UI 组件的时候,他只负责页面渲染的时候,不做任何页面操作的时候,一般可以通过无状态组件定义。
发送异步数据
1 | componentDidMount () { |
Redux-thunk
使得在 action 可以使用异步的代码了
1 | // actionCreators.js |
到底什么是 Redux 中间件
Redux-saga
把异步代码放到 action 中去,这样有利于做自动化测试和代码拆分管理
1 | // actionTypes |
React-Redux 的使用
1 | // index.js |
ActionCreator
相当于 Vue 中的 actions
1 | export function clearInput(state) { |
Reducer
相当于 Vue 中的 mutation
1 | const defaultState = { |
Store
1 | import { createStore } from 'redux' |
Immutable
为了防止 state
在无意中被修改,Immutable
帮助我们生成 immutable
对象,让我们的数据变成 Immutable
对象
因为他已经变成了 Immutable
对象,那么当我们再用这个对象的时候就不能直接使用,需要通过get()
的形式去获取,同理,在更新的时候也需要通过 set 的形式去更新。这时候会结合之前的 Immutable
对象的值和设置的值返回一个全新的对象,并不会改变原始的数据。
这样通过这个库来解决我们在 reducer
中无意修改 state
的错误。
1 | // 使用 fromJS 将 JS 对象转换为 immutable 对象 |
redux-immutable
1 | import { combineReducers } from 'redux-immutable' |
‘摘抄’不是单纯的“粘贴->复制”,而是眼到,手到,心到的一字一句敲打下来。
博客声明:所有转载的文章、图片仅用于作者本人收藏学习目的,被要求或认为适当时,将标注署名与来源。若不愿某一作品被转用,请及时通知本站,本站将予以及时删除。