react
hexo对于{}处理会有问题
1.基础语法
组件必须有一个根节点,组件名字必须大写
内联样式
1 |
|
style如果是对象,要两个{}内嵌,写属性要加引号,fontSize小驼峰
定义虚拟dom时候,不写引号
标签中混入js要用{}
jsx即是js和html混用,{}匹配js,<>匹配html
内联用{}内嵌写法
只有一个根标签
标签需要闭合
写一个不存在的标签
1
2写的小写标签当作浏览器标签识别 <good>
写的大写标签(首字母)当作component组件,如果不存在,报错com is not undefinded如果{}里面是一个数组,可以自动遍历,如果是对象,则出错
表达式和代码
jsx里面{}只能是一个表达式,不能是js代码
- arr.map
- demo(1)
- const a = function(){}
- if
- for
- switch
dom.render()
- react解析组件标签,找到了Mycomponent
- 发现组件时使用函数定义的,随后调用改函数,将返回的虚拟DOM转换为真实DOM,然后呈现在页面当中
2.两种组件写法
函数式写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import ARRCOM from "./arr.js";
import MyClass from "./myclass.js";
function MyApp() {
const arr = ["angular", "react", "vue"];
return (
<div className="myapp">
<header className="App-logo">
{arr.map((item, index) => {
return (
<li key={index}>
{index}:{item}
</li>
);
})}
</header>
<ARRCOM></ARRCOM><MyClass></MyClass>
</div>
);
}
export default MyApp;类写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import React, { Component } from "react";
class MyClass extends Component {
render() {
console.log(this);
return (
<div>
<h1>当前求和为:</h1>
<button>点我+1</button>
</div>
);
}
}
export default MyClass;3.简单/复杂组件
D:组件是否有状态 - 状态驱动页面
ps:需要注意
1
2
3
4State 的更新可能是异步的
出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。
因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。父子组件传参数和生命周期
子组件
1
2
3
4
5
6
7
8
9
10
11
12
13import React, { Component } from "react";
class MyClass extends Component {
render() {
console.log(this);
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}</h2>
</div>
);
}
}
export default MyClass;
父组件
1 | import { Component } from "react"; |
componentWillUnmount组件销毁时候触发,componentDidMount组件挂载的时候触发
ps(注意):
- state和props时预先定义的,你也可以定义别的
- 修改state需要使用到setSate构造函数的方法,别的方法修改报错
- 直接在子组件通过this.props.xxx使用父组件传递的参数
- 这里的合并是浅合并,所以
this.setState({comments})
完整保留了this.state.posts
, 但是完全替换了this.state.comments
。
Official 阻止默认事件
1 | function ActionLink() { |
3.state
存疑
此处this.handleClick = this.handleClick.bind(this)为es6的public class field,handleClick的this执行什么呢?
不写下面那句话的话,this指向underfinded
1 | constructor(props) { |
如果你没有使用public class fields 语法,你可以在回调中使用箭头函数:
1 | class LoggingButton extends React.Component { |
根据逻辑判断进行条件渲染
1 | {unreadMessages.length > 0 && |
之所以能这样做,是因为在 JavaScript 中,true && expression
总是会返回 expression
, 而 false && expression
总是会返回 false
。
类中的方法默认开启严格模式
setState执行的是合并操作,不会把其他属性删除
super(props)的操作,必须在this.xx = xx前面
条件渲染中,当状态改变之后组件重新渲染
state的简写方式
1 | this.demo1 =this.demo1.bind(this) |
在优化函数写法
1 | class Person { |
更新组件的状态 - > 组件重新渲染
4.props
1.props语法糖
1 | let obj = {name:"a", age:23} |
array.reduce() 求和
1 | function sum(..nums){ |
–标签属性类型的限制和非必须限制–
指定默认值–
poops是只读的,单向数据流
对props进行限制 -Person.propsTypes
1 | Person.propTypes = { |
传递方法
1 | Person.propTypes = { |
此种写法写在class外部 - 移除到class内部
1 | class Person extends Component { |
constructor和super
完全可以省略,constructor主要是给state初始化,给实例绑定方法,完全可以使用public class field写法替代。如果写了构造器constructor,一起把super加上,否则会出现问题,
1 | constructor(){ |
构造器是否接受props,传递给super,取决于是否需要在constructor通过this拿到props
函数式组件使用props(只能使用props)
1 | function Person(props){ |
5.refs
通过refs拿到dom
1 | class Person extends Component{ |
三种写法
1.string写法(后续可能被移除
1 | <input ref="getEle"></input> |
tips:提示使用creatRef写法,warning
2.回调写法
1 | <input ref={(dom)=>{this.domNode = dom }}></input> |
ps:回调函数的内联函数写法在组件更新时候(state/条件渲染),会触发两次,第一次获取的domNode为null
–> 改进class的绑定写法
1 | outFn = e => e //错误写法 |
outFn = e => e
拿到的只有当前这个函数,拿不到dom
3.createRef写法
creatRef调用后返回一个容器,改容器可以储存被ref所标识的节点
1 | getEle = React.createRef() |
该容器专人专用(相当于原生获取dom),再次被赋值会被覆盖
关于onClick和onclick
1 | 所有的原生事件都被二次封装 |
jsx的注释不同于其他注释
1 | {/*...js代码*/} |
6.高阶函数
定义:如果一个函数符号下面2个规范中的任何一个,那该函数就是高阶函数
若A函数,接受的是一个函数,那么A就可以称之为高阶函数
若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式
1 | 折叠技巧 |
常见的高阶函数:Promise, setTimeout , array.map
1 | saveFormData = (dataType)=>{ |
非柯里化写法
1 | saveFormData = (dataType,event)=>{ |
原因:onchange函数是被自动调用的,需要的是一个函数,如果写成this.fn()表示调用的是当前函数的返回值
注意:只要组件state修改,组件就会重新挂载-setState
定时器的使用时机:挂载的时候,开启定时器
forceUpdate(强制更新
触发两个钩子
- componentWillUpdate -
- render - ..
- 不更新任何state强制更新
componentWillReceiveProps生命周期
1 | 并不会在第一次传递props调用,只会在porps更新时调用 |
1.初始化阶段
1 | 1.constructor |
2.更新阶段
1 | 1.shouldComponentUpdate() //有一个阀门,必须返回一个boolean,是否继续执行 |
3.销毁阶段
ReactDom.unmountComponentAtNode()触发 –销毁节点
1 | componentWillUnmount() |
常用钩子:
a.componentDidMount()
1 | 1.初始化事件 |
b.componentWillUnmount()
1 | 清理定时器 |
c.render()
bootCDN
7.新版生命周期
新版本可以使用旧的生命周期 - waring-不被推荐使用
UNSAFE_componentWillMount 加入UNSAFE
1 | 需要加UNSAFE |
新版废弃上述三个钩子,新增两个钩子
1.getDerivedStateFromPorps (derived派生)
1 | getDerivefStateFromPorps() |
1.返回null
2.返回object
1 | return {count:108} |
使用场景:即state取决于props
缺点:代码冗余,定时器难以维护,组件难以维护
2.getSnapshotBeforeUpdate
–在最近一次渲染输出(提交到 DOM 节点)之前调用。
(快照)更新之前获取快照 - 任何值都可以为一个快照值
必须返回一个快照,或者null
component
3.diff算法
遍历列表的时候不要使用inde作为key
PS:
简单:key时虚拟Dom对象的标识
详细:当状态中的数据发生改变时,rract会根据新数据生成新的虚拟都没,随后react进行,新老dom进行diff比较
比较规则:
a.旧虚拟dom找到了禹新dom相同的key
1)如果内容没变,那么直接使用之前的dom,
2)如果不同的话,则生成新的dom,替换旧的dom
b.index作为key,可能会引发的问题、
1.索引值被打乱,造成无用的dom更新(效率低,无用的资源浪费
2.需求:
4.样式冲突(模块化解决
后面引入的覆盖之前引用的
less 嵌套
1 | import hello from './a.module.css' |
这样之后当前css的样式都以对象的形式,包含在hello里面
1 | <div class = {hello.title}></div> |
此时title为类选择器,如果为其他选择器怎么办?
1 | .title{ |
5.插件使用
代码块
6.受控组件和非受控组件浅析
checkout 可以写一个defaultValue,后续defaultChecked的值可以改,如果使用checked,则必须使用onChange来改变checkout选中状态,此处defaultChecked的写法就是非受控组件,而使用onChange函数自己改变状态的,则是受控组件
解构技巧
const {…} = this.props
const {…} = this
7.组件传参
父子组件传参
1
2
3
4
5<item todos={todos}>
//父组件将其内部的变量 todos传给子组件items,子组件接受到的值为todos
<item {...todos}>
//解构写法 - 将todos这个对象的值逐一的传递到子组件
子传父
1
原理:父组件向子组件传递一个函数(通过props),然后子组件调用当前函数
id库
1
2uuid - 唯一id
nanoid - 比uuid库小,功能一样
浅拷贝小tips
1 | let obj = {a:1,b:2} |
todolist案例中更改状态
1 | updateTodo = (id,done) => { |
array.reduce()
8.消息订阅与发布
订阅与取消订阅
1 | componentDidMount() { |
发布消息
1 | PubSub.publish("publish_one", data.data.items); |
PS:注意在需要消息的地方订阅,在传递数据的地方发布消息,记得在组件销毁之前取消订阅
fetch
- xhr(传统ajax)
- jquery
- axios
- fetch
- 关注分离(复杂的事情简单化
关注分离具体到发送请求:将请求服务器和拿到数据分开处理
1 | fetch(`url`).then(response=>{ |
fetch使用较少,老版本浏览器不支持fetch请求
8.路由(旧版
SPA:单页面应用
只有一个页面
无刷更新数据
数据请求,异步展示
1.react-router-dom 5
1 | //#1 |
路由器分类
- BrowserRouter
- HashRouter
1.link
1 | <BrowserRouter> |
link都需要被router包裹,故在最大的app外面包裹browserRouter
link被转化为A标签,
2.navlink
当前被点击的内容加一个navlink类名(默认,可以加一个activeClassName绑定一个类名
3.switch
1 | <switch> |
用switch包裹的组件集合,匹配到了第一个就不会往下匹配,
Switch可以提高路由匹配效率(单一匹配)。
4.多级路由的样式更新问题
1.public/index.html 中 引入样式时不写 ./ 写 / (常用)
2.public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用)
3.如果是hasuRouter则没有问题
5.模糊匹配
1 | <NavLink |
当前情况下跳转至/http/aa可以匹配到Basic组件(模糊匹配),而不能匹配到/a/http/aa
严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
精准匹配
1 | <Route extra={true} path="/http" component={Basic} /> |
重定向Redirect
1 | <switch> |
当http,input都无法匹配的时候,重定向到..
一般把redirect写在所有的路由下方,当所有的都无法匹配时候,redirct—
6.嵌套路由
PS:不能使用严格匹配,会导致路由丢失
- 注册子路由时候,加上父路由的path值
- 路由的匹配是按照注册路由的顺序进行的
7.向路由组件传参
1 | <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> |
params传参
1
2<link to='demo/18/zhangsan'/>
<Route path='demo/:id/name'接受参数: this.props.match.params
search传参
1
2<link to='demo?id=18&zhangsan'/>
<Route path='demo'/>接受参数:this.props.location.search
state传参
1
2<link to='demo' state={name:"tom"}/>
<Route path='demo'/>接受参数:this.props.location.state
8.编程式导航
1 | this.prosp.history.push() this.prosp.history.replace() this.prosp.history.goBack() |
BrowserRouter与HashRouter的区别
- 兼容性
- 不支持IE9及下
- 使用的 URL的哈希值
- path
- 路径没有#
- state的影响
- browserRouter无影响
- HashRouter刷新后导致路由state参数的丢失
- 可以解决路径错误问题
withRouter
一个函数
1 | export default withRouter(myApp) |
使一般组件具有路由路由组件特有的api,返回值是一个新组件
9.使用antd组件库
1 | // npm i antd |
注意有的版本导入antd.css会有问题,此处改为antd.min.css
10.redux
*:只要调用setSate,就能更新状态,更新dom
redux:只能管理状态,但不会触发更新
1 | componentDidMount(){ |
setState存在效率问题,此处是一个小技巧
1.监听单个组件
redux 文件夹下
1.store.js
1 | import {createStore} from 'redux' |
2.count_reducer
1 | const initState = 0 //初始化状态 |
第一次调用的时候,preState为underfinded,因此需要赋一个默认值
3.use.js 使用store
1 | componentDidMount(){ |
此处一个重要的点就是监听store状态,只要改变了,就触发setState更新视图,可以将监听放在index.js里面,进行全局监听
1 | store.subscribe(()=>{ |
此处有diff算法兜底,不会造成大未改变页面更新
pnpm使用
使用 pnpm install
安装项目依赖时出现:ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies
问题原因:在 npm 3 中,不会再强制安装 peerDependencies (对等依赖)中所指定的包,而是通过警告的方式来提示我们。pnpm 会在全局缓存已经下载过的依赖包,如果全局缓存的依赖版本与项目 package.json 中指定的版本不一致,就会出现这种 hint 警告。
处理方案
在项目的
package.json
中配置peerDependencyRules
忽略对应的警告提示:1
2
3
4
5
6
7"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"react"
]
}
}在
.npmrc
配置文件中添加strict-peer-dependencies=false
,这意味着将关闭严格的对等依赖模式。操作命令如下:1
npm config set strict-peer-dependencies=false
箭头函数补充
1 | data => 1 //返回1 |