旧的生命周期方法
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
1. constructor() 2. componentWillMount() 3. render() 4. componentDidMount() - 更新阶段:由组件内部this.setState()或父组件render触发
/** * 0. componentWillReceiveProps()会在父级重新渲染调用 */ 1. shouldComponentUpdate() 2. componentWillUpdate() 3. render() 4. componentDidUpdate() - 卸载组件:由ReactDom.unmountComponentAtNode()触发
1. componentWillUnmount()
总结:旧的废弃了componentWillReceiveProps,componentWillMount,componetnWillUpdate,新增 static getDerivedStateFromProps(props, state),getSnapshotBeforeUpdate
新的生命周期
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
1. constructor() 2. getDerivedStateFromProps 3. render() 4. componentDidMount() - 更新阶段:由组件内部this.setState()或父组件重新render触发
/** * 0. componentWillReceiveProps()会在父级重新渲染调用 */ 1. getDerivedStateFromProps 2. shouldComponentUpdate() 3. render() 4. getSnapshotBeforeUpdate 5. componentDidUpdate() - 卸载组件:由ReactDom.unmountComponentAtNode()触发
1. componentWillUnmount()
JSX嵌入变量
- 当变量是Number,String,Array类型时,可以直接显示
- 当变量是null,undefined,boolean类型时,内容为空
React-router-dom 路由
1.activeClassName 设置激活路由样式
2.路由组件:接收到三个固定的属性
history:
go: fn go(n)
goback: fn goback()
goForward: fn goForward()
push: fn push(path,state)
replace: fn replace(path,state)
location:
pathname: "/about"
search: ""
state: undefined
match:
params: {}
path: "/about"
url: "/about"
Switch的使用
Switch 包裹 标签可以提高路由匹配效率(单一匹配)
路由的严格匹配与模糊匹配
1.默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
2.开启严格匹配:<Route exact={true} path="/about" component={About}/>
3.严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
Redirect的使用
1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,挑战到Redirect指定的路由
2.具体编码
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
向路由组件传递参数
1.params参数
路由链接(携带参数):<Link to='/demo/test/tom/18'>详情</Link>
注册路由(声明接收):<Route path='/demo/test/:name/:age" component={Test}/>
接受参数: const {id,title} = this.props.mathch.params
2.search参数
路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数: const {search} = this.props.location
备注: 获取到的search是urlencoded编码字符串,需要借助querystring解析
3.state参数
路由链接(携带参数):<Link to={{path:'/demo/test'},state:{name:'tom',age:18}}}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:const { state } = this.props.location
备注:刷新也可以保留住参数,参数保存在history对象上,清空缓存失效
给一般组件传递路由组件的api
import {Component} from 'react'
import {withRouter} from 'react-router-dom'
class Header extends Component
export default withRouter(Header)
通过withRouter给普通组件包裹下
BrowserRouter与HashRouter的区别
1.底层原理不一样: BrowserRouter使用的是H5的histroy API,不兼容IE9及以下版本。 HashRouter使用的是URL的哈希值 2.path表现形式不一样 BrowserRouter的路径中没有# HashRouter的路径中包含# 3.刷新后对路由state参数的影响 BrowserRouter没有任何影响。因为state保存在history对象中 HashRouter刷新后会导致路由state参数的丢失
Hooks
useEffect
- 会在首次
render的之后必定执行一次 - 如果返回了函数,那么在下一次
render之前或组件unmount之前必定会运行一次返回函数的代码 - 如果指定了依赖数组,且不为空,则当数组里的每个元素发生变化时,都会重新运行一次
- 如果数组为空,则只在第一次render时执行一次
- 如果在useEffect中更新了state,且没有指定依赖数组,或state存在与依赖数组中,则会造成死循环
useState
- 函数式组件每次重新渲染时
[count,setCount] = useState(1),setCount都是全相等
Redux
- 通过
redux的createStore(reducer)创建一个store - 通过
store.dispatch派发action - 通过
store.getState()获取reducer的state - 通过
store.subscribe(fn)订阅派发事件,,state变化触发更新
函数式组件
- 函数式组件会重新执行,方法内的局部变量(函数,对象)不全等
Generator
// 2.生成器函数的定义
// 生成器函数
function* foo() {
console.log("111");
yield "Hello";
console.log("222");
yield "World";
console.log("333");
yield "coderwhy";
console.log("444");
}
// iterator: 迭代器
const result = foo();
console.log(result);
// 3.使用迭代器
// 调用一次next, 就会消耗一次迭代器
// const res1 = result.next();
// console.log(res1);
// const res2 = result.next();
// console.log(res2);
// const res3 = result.next();
// console.log(res3);
// const res4 =result.next();
// console.log(res4);
// 4.生成器函数中代码的执行顺序
// 5.练习: 定义一个生成器函数, 依次可以生成1~10的数字
function* generateNumber() {
for (var i = 1; i <= 10; i++) {
yield i;
}
}
// const numIt = generateNumber();
// console.log(numIt.next().value);
// 6.generator和Promise一起来使用
function* bar() {
console.log("1111");
const result = yield new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello Generator");
}, 3000);
});
console.log(result);
}
const it = bar();
it.next().value.then(res => {
it.next(res)
})
记录
setState同步异步
setState在合成时间和生命周期中是异步的,这里说的异步其实是批量更新,达到了优化性能目的 2.setState在setTimeout和原生事件中是同步的 3.在setState(fn,callback)中是同步的
React开发项目遇到问题
页面打开播放音乐报错<audio/>标签,不允许打开网页时就播放音乐
/**
* audio标签事件
* onEnded 当歌曲播放完的时候
* onTimeUpdate 当歌曲播放时的时间 毫秒
* audio.currentTime 当前歌曲播放时间 毫秒
*/
const [isPlaying, setIsPlaying] = useState(false)
useEffect( () => {
audioRef.current.src = getPlaySong(currentSong.id)
audioRef.current.play().then(res=>{
setIsPlaying(true)
}).catch( err=> {
setIsPlaying(false)
})
},[currentSong])
const playMusic = useCallback(() => {
setIsPlaying(!isPlaying)
isPlaying ? audioRef.current.pause() : audioRef.current.play()
},[isPlaying])
Css Model小技巧
在TSX中引用css类选择或者id选择器,需要安装插件typescript-plugin-css-modules
npm install typescript-plugin-css-modules -D
然后在tsconfig.json中添加配置
"compilerOptions":{
"noImplicitAny": false,//参数没有设置类型,自动为any类型
"plugins": [
{
"name": "typescript-plugin-css-modules"
}
]
}
同时在 vscode 当前项目根目录下新建 .vacode/settings.json,内容如下
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
react-i18next
npm install react-i18next i18next --save
Redux中间件公式
const middleware = (store) => (next) => (action) =>{}, 如下,打印日志的中间件
import { Middleware } from "redux"
const actionLog: Middlleware = (store) => (next) => (action) => {
console.log("state 当前 ", store.getState())
console.log("fire action ", action)
next(action)
console.log("state 更新", store.getState())
}
在JSX中加载html
dangerousllySetInnerHTML
<div dangerouslySetInnerHTML={{__html:'<span>abc<span>'}}></div>
centos docker 安装
//安装 yum 源
yum update
yum install epel-release -y
yum clean all
yum list
yum install docker-io -y
systemctl start docker
docker info //查看启动结果
docker 阿里云镜像加速器
- 打开登录阿里云官网,并登录
- 点击右上角
控制台 - 打开
产品与服务,选择容器服务镜像
4. 点击侧边栏
镜像工具:镜像加速器,按照操作文档来即可