# 组件和jsx
## react组件
jsx文件,里面是jsx语法生成的dom
## jsx语法
jsx除了是文件后缀外,在组件内还是一种语法。
`<img/>`这个jsx语法是`React.createElement('img')`语法糖
## 样式绑定
类名样式:className
内联样式/行内样式:`style={{color:'red'}}` 第一个括号表示表达式,第二个是对象
## 样式作用域
- 默认情况下,样式在组件内引入后,作用域是全局的;
- 使用name.module.css命名样式后,作用域就只是当前组件内生效;
## 资源引入img
背景图就是使用相对路径
前景图img用`require('相对路径').default`
## React组件三种写法
- function无状态组件,只接受一个props
- class es6的写法,继承React.Component
- hook新特性,让函数组件拥有全部react特性
- 【废弃】createClass
# api和指令
## dangerouslySetInnerHTML/非dom属性
- 渲染字符串dom片段的,底层做了防注入攻击了。
- 但是一般很多情况下,不推荐使用。
## React.createElement
创建虚拟dom的,`<div/>`jsx语法是它的语法糖,也就是对他的封装。
## React.Component
创建类组件的基类,包含着全部react特性
## React.Fragment
- 占位的点组件,用于包裹集合元素
- 优点:不会渲染成任何标签
- 缩写:`<></>`
# 属性和状态
## 属性 props
- 属性,规则:自定义属性必须全部小写;
- 原生的属性需要额外的注意:class变成了className/for变成了htmlFor/tabindex变成了tabIndex
### 属性默认值
App.defaultProps={prop:defaultValue}
### 属性类型验证
需要引入`prop-types`包依赖。
App.propTypes={prop:propTypes.String}
### 属性的入参写法
- 写在普通的虚拟dom上的叫属性
- 写在自定义组件上的是传参方式
- 参数值的类型有:字符串、数组、数字、布尔值等;如果是对象类型的话,需要使用扩展运算符展开。
## state
- 状态,和vue里的data一样的功能。
- 修改state只能用setState
# 事件函数
1. 在class类里,事件函数的this指向问题
- 三种解决方案:
- 直接在事件绑定函数后面加`.bind(this)`【不推荐,每次点击bind一次,消耗性能】
- 在constructor里事先绑定`.bind(this)`
- 声明函数的时候使用箭头函数绑定this
# 生命周期
## 概念
- 生、老、病、死===人的生命周期
- 初始化、挂载、更新、销毁===程序的生命周期
## 定义
事物的不同阶段发生变化叫做生命周期
## api
- constructor 初始化阶段
- render 解析jsx语法阶段
- componentDidMount 完成挂载
- componentDidUpdate 完成更新
- componentWillUnmount 完成卸载
- static getDerivedStateFromProps(props,state) 修改state值
- 通过props计算出来的state值,它会覆盖掉setState设置state值
- 在挂载阶段和更新阶段都会触发
- 返回对象则替换state,返回null则不修改任何数据
- shouldComponentUpdate(props,state)
- 性能优化的一部分
- 执行时机:当props和state发生改变时,还没有在render里体现的时候;
- 默认返回true,返回false则阻止render的执行,也就相当于阻止更新了。
- getSnapshotBeforeUpdate(prevProps,prevState)
- 获取dom元素的
- 入参是上次的旧值
- 执行时机:render执行后执行
- 在最近一次渲染输出(提交DOM节点)之前调用。它使得组件能在发生更改之前从DOM中捕获一些信息(例如,滚动位置)此生命周期的任何返回值将作为参数传递给componentDidUpdate
- componentDidCatch(error,info){} 捕获子组件错误的函数
# hook
- 是react自16.8版本后新出的一套api,其目的是为了让函数组件拥有全部的react特性。
## 设计思想
- 函数式编程
## useState
- 状态管理
- 语法:`const [value,setValue] =useState(defaultValue)`
- 定义:让函数组件拥有和类组件一样的状态
- 数组里的第一个值是渲染到页面上的数据state,后面的值是用来修改前面数据的方法,等价于类组件里的setState
- 不能直接修改value,只能用setValue去修改,这样才能让组件进入更新
- 【注意】:
- useState返回的修改函数和类组件setState执行逻辑不一样
- setState是把新旧值合并,useState返回的修改函数是用传进来的新值直接把旧值替换了
## useEffect 生命周期
- 定义:把componentDidMount、componentDidUpdate、componentWillUnmount、shouldComponentUpdate合并成一个叫做useEffect函数了。
### componentDidMount
```js
useEffect(function(){
console.log('页面挂载完成')
},[])
```
### componentWillUnmount
```js
useEffect(()=>{
return function(){
//这个函数就是当组件被销毁的时候调用的,在这个函数里做准备卸载的一些事情,比如清除定时器之类的
}
})
```
### componentDidUpdate
```js
useEffect(function(){
console.log('当props或state发生改变时,这个函数就相当于更新的钩子函数')
})
```
### shouldComponentUpdate
```js
useEffect(()=>{
console.log('只有老谢发生改变,我才执行')
},[老谢,obj.name])
```
# 受控与非受控
## 受控组件
- 受react控制的叫受控组件
- 举例:当一个input的value绑定了state,那么该组件叫做受控组件。
## 非受控组件
- 不受react控制的,行为完全由用户控制的叫非受控组件。
- 举例:input类型是file的就是纯粹的非受控组件
- defaultValue给非受控组件添加一个初始值,但不影响更新
- ref获取非受控组件节点,进行操作或读取
# React.lazy
- 使用lazy动态加载组件,使用Suspense包裹被懒加载的组件
- 语法:
```js
const Home=React.lazy(()=>import('path/Home.jsx'))
//当Home组件尚未加载完成前,显示备用内容
return <React.suspense fallback={备用内容(可以是字符串、标签)}>
<Home></Home>
</React.suspense>
```
# context
- 上下文对象:跨级通信
- 概念:传统的层级组件通信,需要每一层组件写props传递,如果其中某一层组件没有传递props,就导致断层通信。
- 适用:
- 中小型项目。
- 大型项目还是使用redux或者mobx集中管理。
- 上下文对象需要根元素提供数据,如果数据源来自多个组件的话,就不适合使用context了。
- 当数据源是单一的情况下,使用context比较方便。
# 语法
```js
//context.js 创建共享的上下文对象
const context=React.createContext()
```
```js
//根组件:上下文组件数据提供者
<context.Provider value={data}>
<MySub/>
</context.Provider>
```
```js
//数据的使用者:后代组件MySub.jsx
//上下文组件渲染者
// *Consumer里面必须是一个带返回值的函数
<context.Consumer>
{
(data)=>{
return <div>
{...data}
</div>
}
}
</context.Consumer>
```
## useContext
- 使用它可以省略掉Consumer组件,而直接获取到Provider提供的数据,【但是】会破坏掉性能优化的memo和shouldComponentUpdate
# ref
- 定义:react里的所有组件都有一个ref属性,用于获取组件实例或dom对象。
- 一般必须操作dom的时候才会用到,非必要不推荐使用。
## ref的四种参数
1. React.createRef() 【不可以设置默认参数】【考点】
2. useRef() 【可以设置默认参数】
3. 回调函数
4. 字符串【历史遗留的api】
## ref使用
- 如果给类子组件使用ref,获取的是类组件的实例对象。如果用在纯函数组件上,则会报错,要求必须使用React.forwardRef()
## ref转发
- forwardRef用于获取子组件中的dom元素
- 语法:
```js
forwardRef((props,ref)=>{
return <input ref={ref} type='text'/>
})
```
# 高阶组件
- 它不是api,是一种组合模式。目的是为了复用类组件里的方法。
- 定义:一个函数,接收一个组件,返回一个类组价就叫高阶组件。
## 注意
- 高阶组件初始化的时候,不能写在render或return里,不然就报错了。
## hoc高阶组件转发
1. 高阶组件:一个函数接收一个组件,返回一个类组件
2. 作用和目的:复用类组件的方法和事件
3. 早期函数组件没有生命周期和状态,都是使用这种组合【策略】模式去实现复杂的组件开发
- 在Hoc函数中,使用forwardRef将类组件返回,并传入上游注入的ref对象进行绑定。
1. 组件
- props:是react组件的输入,他们是从父组件向下传递给子组件的数据,并且子组件无法修改,
- props.children:是一个集合
2. 顶级API
- 定义:凡是挂载在全局对象React下面的方法和属性都叫顶级Api
- React.createElement:创建虚拟dom,接收三个参数('html原生标签','属性','内容或子组件')
- React.Children:提供了用于处理 this.props.children 不透明数据结构的实用方法。
# mobx
1. state
2. setState(action)
3. view(函数、事件、调用)
- 可以有一个store也可以有多个
- 任意子组件,只要调用当前store.js,都可以把当前的信息返回到store.js
1. @observable
- store.js
- this.state
- 可以被读取,也可以被修改
2. @observer
- view
- view 页面中,主要是为了让页面变成响应式,能读取和操作store
3. @action
- store.js
- this.setState 修改@observable
# redux
1. state
2. action(唯一修改state的方式、行为)
3. reducer(生成state)
4. views(函数、事件、调用)
- 只能有一个Store,由多个state片段生成的state
## 使用dispatch 两种方式
一是直接使用
connect(mapStateToProps,null)(View);
第二个参数 为空,这样页面直接可以使用this.props 使用
二是使用mapDispatchToProps
export default connect(mapStateToProps,mapDispatchToProps)(View);
直接使用 mapDispatchToProps 内的方法
# 其他
##PS
- 基础操作
-- 编辑里的首选项 单位与标尺选择像素
-- 点击窗口可以选择信息、历史记录
- 快捷键s
-- z:放大镜,Alt:缩小
-- ctrl+shift+c 复制图层
-- ctrl+n 新建
-- ctrl+v 粘贴
-- ctrl+alt+shift+s 保存
-- 转为智能对象
## props使用场景
- 直接使用它的数据类型(父传子)
- this.props.children 接收父组件传入的数据
- 接收组件
```html
<Child left={<left title=''></left>}/>
```
- 子传父 用callback函数