美文网首页
2019-11-02React高阶组件学习踩坑

2019-11-02React高阶组件学习踩坑

作者: 菩灵 | 来源:发表于2019-11-27 15:54 被阅读0次

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值生成

image.png

PureComponent的state和props前后对比

image.png
image.png

由于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>
}
image.png
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增加/修改属性
image.png
// 复合组件(相当于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属性


image.png

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代码书写过程中,起别名直接用:

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(没有值)

解构赋值和导入起别名区别

解构的时候起别名用:
image.png
导入的时候起别名:

1、export导出


image.png

2、export导入:


具名导入所有模块起别名
3、import导入:
具名改别名

相关文章

  • 2019-11-02React高阶组件学习踩坑

    react+mobx+antd按需加载 出现Support for the experimental syntax...

  • React——第三阶段(1)(高阶组件、context)

    根据胡子大哈的文章学习,感谢大胡分享胡子大哈-高阶组件、context 高阶组件 什么是高阶组件 高阶组件就是一个...

  • react高阶组件

    此篇文章准备从高阶组件的概念出发,通过应用场景结合例子来学习react的高阶组件。 何为高阶组件 在开发 Reac...

  • React-Native 高阶组件

    高阶函数 高阶组件(属性代理)普通组件还可以向高阶组件传值 高阶组件(反向继承) 普通组件的 static 方法怎...

  • React高阶组件HOC

    高阶组件本质是函数,参数是 组件1 返回组件2,高阶组件是为了复用通用逻辑高阶组件eg:import React,...

  • react与vue中高阶组件的对比

    由高阶函数引申出来的高阶组件 高阶组件本质上也是一个函数,并不是一个组件,且高阶组件是一个纯函数。高阶组件,顾名思...

  • 2021-08-05-🦕🦕 react 高阶组件hotc和@装饰

    简介 高阶组件可以直接调用子组件属性方法;子组件通过 this.props.xxx调用高阶组件方法属性 高阶组件无...

  • React 高阶组件(HOC)

    什么是高阶组件? 高阶组件(Higher-Order Components,简称HOC):简而言之,高阶组件就是加...

  • 高阶组件

    高阶组件 先来引入这个概念 高阶函数是什么? 高阶函数就是一个函数返回一个函数eg: 高阶组件 类同 高阶组件就是...

  • React 进阶之高阶组件

    高阶组件 HOC 高阶组件(HOC)是react中的高级技术,用来重用组件逻辑。但高阶组件本身并不是React A...

网友评论

      本文标题:2019-11-02React高阶组件学习踩坑

      本文链接:https://www.haomeiwen.com/subject/huthbctx.html