react+mobx+antd按需加载 出现Support for the experimental syntax 'decorators-legacy' isn't currently enabled
baidu上面的说法大多是在 项目的package.json 中添加decorators-legacy
因为引入了antd的按需加载 所以只需要在config-overrides.js中添加addDecoratorsLegacy()
const { override, fixBabelImports, addDecoratorsLegacy } = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}),
addDecoratorsLegacy(),
);
对象的key值生成

PureComponent的state和props前后对比


由于shouldComponentUpdate上第一个校验规则是前后的值完全相等(值类型值相等,引用类型地址相等),如果引用类型前后的值相等但是地址不等,仍然会认为是不等的,继续更新
所以,使用的时候props和state避免传入与引用类型
React高阶组件书写模式
1、普通生成
// 高阶组件
import React from 'react'
function Kaikeba(props){
return <div>{props.stage}---{props.name}</div>
}
const withKaikeba = Comp => {
const name="高阶组件"
return props => <Comp {...props} name={name}></Comp>
}
const NewKaikeba = withKaikeba(Kaikeba)
class Rong extends React.Component{
constructor(props){
super(props)
this.state={
stage:"React"
}
}
render(){
return <NewKaikeba stage={this.state.stage}></NewKaikeba>
}
}
export default Rong
2、 高阶组件中改写原组件生命周期
const withKaikeba = Comp => {
const name="高阶组件"
return class extends React.Component{
componentDidMount(){
console.log("do something")
}
render(){
return <Comp {...this.props} name={name}></Comp>
}
}
}
3、不止一个高阶组件进行强化
const withLog = Comp => {
console.log(Comp.name+"渲染了");
return props => <Comp {...props}></Comp>
}
- // const NewKaikeba = withKaikeba(Kaikeba)
+ const NewKaikeba = withLog(withKaikeba(withLog(Kaikeba)))
4、高阶组件简洁写法
- const NewKaikeba = withLog(withKaikeba(withLog(Kaikeba)))
import React from 'react'
const withKaikeba = Comp => {
const name="高阶组件"
return class extends React.Component{
componentDidMount(){
console.log("do something")
}
render(){
return <Comp {...this.props} name={name}></Comp>
}
}
}
const withLog = Comp => {
console.log(Comp.name+"渲染了");
return props => <Comp {...props}></Comp>
}
@withLog
@withKaikeba
@withLog
class Kaikeba extends React.Component{
render(){
return <div>{this.props.stage}---{this.props.name}</div>
}
}
// const NewKaikeba = withKaikeba(Kaikeba)
// const NewKaikeba = withLog(withKaikeba(withLog(Kaikeba)))
class Rong extends React.Component{
constructor(props){
super(props)
this.state={
stage:"React"
}
}
render(){
return <Kaikeba stage={this.state.stage}></Kaikeba>
}
}
export default Rong
神奇:高阶组件多重装饰之后,只要引入,哪怕不挂在到页面上,都会执行装饰器中的函数
image.png
image.png
React复合组件写法
1、props.children作为一个属性
// 复合组件(相当于vue中的slot插槽)
import React from 'react'
function Dialog(props){
return <div style={{border:`2px solid ${props.color || "blue"}`, color:"pink"}}>{props.children}</div>
}
function WelcomeDialog(props){
return <Dialog {...props}>
<h1>欢迎光临</h1>
<p>下午好</p>
</Dialog>
}
export default function(){
return <WelcomeDialog color="lightGreen"></WelcomeDialog>
}

2、props.footer添加一个具名插槽
const footer = <Button onClick={() => alert("确定提交!")}>确定</Button>
return <WelcomeDialog color="lightGreen" footer={footer}></WelcomeDialog>
<div style={{border:`2px solid ${props.color || "blue"}`, color:"pink"}}>
{props.children}
<div className="footer">
{props.footer}
</div>
</div>
3、props.children作为一个函数--->作用域插槽)
// 作用域插槽
const Api = {
getUser(){
return { name: "jerry", age: 18 }
}
}
function Fetcher(props){
const user = Api[props.name]()
return props.children(user)
}
<Fetcher name="getUser" >
{({name, age}) => (
<p>
姓名:{name}<br></br>
年龄:{age}
</p>
)}
</Fetcher>
4、props.children增加/修改属性

// 复合组件(相当于vue中的slot插槽)
import React from 'react'
import { Button } from 'antd'
function Dialog(props){
return (
<div style={{border:`2px solid ${props.color || "blue"}`, color:"pink"}}>
{props.children}
<div className="footer">
{props.footer}
</div>
</div>
)
}
function WelcomeDialog(props){
return <Dialog {...props}>
<h1>欢迎光临</h1>
<p>下午好</p>
</Dialog>
}
// 作用域插槽
const Api = {
getUser(){
return { name: "jerry", age: 18 }
}
}
function Fetcher(props){
const user = Api[props.name]()
return props.children(user)
}
function Filetr({ children, type }) {
{ React.Children.forEach(children, child => {
console.log(child);
// child.props.children="都给我统一"
}) }
return (
<div>
{/* { React.Children.forEach( children, child => {
console.log(React.Children);
if(child.type === type){
return;
}else{
return child
}
} ) } */}
{ children }
</div>
)
}
function RadioGroup(props){
return (
<div>
{ React.Children.map( props.children, child => {
return React.cloneElement(child, { name: props.name })
} ) }
</div>
);
}
function Radio({ children, ...rest }){
return (
<label>
<input type="radio" {...rest}/>
{ children }
</label>
);
}
export default function(){
// const footer = <Button onClick={() => alert("确定提交!")}>确定</Button>
// return <WelcomeDialog color="lightGreen" footer={footer}></WelcomeDialog>
return (
<div>
{/* <Fetcher name="getUser" >
{({name, age}) => (
<p>
姓名:{name}<br></br>
年龄:{age}
</p>
)}
</Fetcher>
<Filetr type="p">
<p>这是个p</p>
<h1>这是h1</h1>
<p>这又是个p</p>
<h1>这又是个h1</h1>
</Filetr> */}
<RadioGroup name="mvvm">
<Radio value="vue">vue</Radio>
<Radio value="react">react</Radio>
<Radio value="angular">angular</Radio>
</RadioGroup>
</div>
);
}
此时,子元素里面除了value外,也多了name属性

ReactHook
useEffect副作用
是一个函数,相当于渲染过程中的三个生命周期,第一个参数是一函数(需要执行的事件),第二个参数是与此相关的状态(空:所有状态改变都执行;[]:所有状态改变都不执行;['count']:只有count改变才执行)
自定义钩子
// 自定义钩子
function useAge(){
const [ age, setAge ] = useState()
useEffect(() => {
setTimeout(() => {
setAge(21)
},2000)
})
return age
}
const age = useAge()
<p>年龄是{age ? age : "loading..."}</p>
Context上下文使用(使用场景:隔代传参)
import React, { useContext } from 'react'
// 创建上下文
const MyContext = React.createContext()
const { Provider, Consumer } = MyContext
function Child(props) {
return (
<div>
{ props.foo }
</div>
)
}
function Child2(props){
const ctx = useContext(MyContext)
return (
<div>
{ctx.foo}
</div>
);
}
class Child3 extends React.Component {
static contextType = MyContext
render(){
return (
<div>{ this.context.foo }</div>
);
}
}
export default function ContextTest() {
return (
<div>
<Provider value={{foo:"bar"}}>
<div>
{/* 隔代传参第一种方式:Consumer */}
<Consumer>
{ value => <Child {...value}></Child> }
</Consumer>
{/* 隔代传参第二种方式:钩子 */}
<Child2></Child2>
{/* 隔代传参第三种方式:class */}
<Child3></Child3>
</div>
</Provider>
</div>
)
}
React代码书写过程中,起别名直接用:

generator初始化函数与.next()传值时机
function* figer(num){
let b = "这是一个b"
setTimeout(()=>{
console.log("异步函数执行");
// return "return 一个 value"
})
console.log(b);
let a = yield num;
console.log(b);
console.log(a);
yield num + 1
}
let it = figer(2)
console.log(it);
// console.log(it.next()); // { value: undefined, done: false }
console.log(it.next('给a传值'));
console.log(it.next());
console.log(it.next());
// generator函数接收函数外面的值在初始化阶段调用时传递
// generator函数的第一个.next()调用,只执行第一个yield函数之前的非异步函数(未yield的异步函数在最后)
// 并执行这第一个yield后面的表达式,并返回一个{value:xxx,done:Boolean}
// generator的第二个.next()调用,执行第二个yield函数之前的非异步函数
// 并执行当前的yield函数,并将此.next()传入的参数赋值给第一个yield函数之前的表达式接收值
// 如果在第二个.next()执行的时候不传入值,则第一个yield表达式之前的接收值为undefined(没有值)
解构赋值和导入起别名区别
解构的时候起别名用:

导入的时候起别名:
1、export导出

2、export导入:

3、import导入:

网友评论