zoukankan      html  css  js  c++  java
  • React-学习总结

    1、学习一个框架的目的,在于使用它产出价值

    如何熟练的使用,是产出多少价值的关键

    2、框架的使用,有其自己的一套规范,那么我们如果熟知规范和使用方法

    那么学习框架的目的你就达到了

    备注:至于使用过程中,遇到框架本身的问题,那么就需要研究其源码了,这里我们暂且不讨论

    react 优化与注意事项

    框架有其规则,对于经验丰富的老手来说,上手并不难,难得是各种坑
    这里我记录下react的使用方法,以及各种注意点

    react 渲染

    • 使用 ReactDOM渲染
    • 可以使用 js 作为文件后缀,不必要求 jsx 后缀
    • 因为 create-react-app 脚手架做了配置
    • 其内部使用的 webpack 打包,配置了 babel-preset-jsx 用来转换 jsx 语法
    // App.js
    import ReactDOM from 'react-dom'
    import React, { Component } from 'react'
    export default class App extends Component {
        render() {
            return (
                <div>App comp</div>
            )
        }
    }
    ReactDOM.render(<App/>, document.querySelector('#root'), () => {
        console.log('渲染完成')
    })
    

    jsx 语法

    // App.js
    import ReactDOM from 'react-dom'
    import React, { Component } from 'react'
    // 约定子组件首字母大写,方便区分原生标签,查找组件
    import SonComp from './component/SonComp'
    export default class App extends Component {
        render() {
            const message = 'message'
            const dangerHtml = '<h1>标题</h1>'
            const visiable = true
            const arr = [1, 2, 3]
            const obj = {
                a: 1,
                b: 2,
                c: 3
            }
            return (
                <div>
                    // 渲染 App comp 字符串
                    <div>App comp</div>
                    
                    // 渲染变量 message
                    <div>{ message }</div>
                    
                    jsx 支持在双大括号{}里书写 js 语法逻辑
                    <div>{ message === '' ? '空' : message }</div>
                    { visiable && <SonComp /> }
                    <div>{ message.split('') }</div>
    
                    // 渲染数组
                    <ul>
                    {
                        arr.map((item, index) => {
                            // 这里key本不该用 index
                            // 需要使用业务的唯一值
                            // react 用来做复用,做性能优化
                            return <li key={index}>{item}</li>
                        })
                    }
                    </ul>
    
                    // 渲染对象
                    <ul>
                    {
                        (() => {
                            let tagArr = []
                            for (const key in obj) {
                                if (Object.hasOwnProperty.call(obj, key)) {
                                    tagStr.push(<li key={key}>{obj[key]}</li>)
                                }
                            }
                            return tagArr
                        })()
                    }
                    </ul>
                    
                    // 设置类名与添加类名
                    <div className={`wrapper${ visiable ? 'visiable' : ''}`}>App comp</div>
                    
                    // 设置样式,第一层{}表示要解析当前字符串
                    // 第二层表示对象
                    <div style={{  '100px', height: '100px', border: '1px solid black' }}>
                        App comp
                    </div>
                    
                    // 相当于 vue 的 v-html
                    <div __html={dangerHtml}></div>
                    <div dangerousSetInnerHTML={{__html: dangerHtml}}></div>
                    
                    // 子组件
                    <SonComp />
                </div>
            )
        }
    }
    ReactDOM.render(<App/>, document.querySelector('#root'))
    

    事件绑定

    • 在 react 中,event 事件对象是 react 自身封装的合成对象
    • 而不是 DOM 的原生 js 事件对象
    • 可以通过 event.nativeEvent 拿到原生事件对象
    • react 中,将事件挂在 document 上,通过事件委托触发
      • 可对比 event.currentTarget(这里为:当前触发元素)、event.nativeEvent.currentTarget(这里为:document)
    import React, { Component } from 'react'
    export default class App extends Component {
        constructor() {
            this.btnActionBind = this.btnAction4.bind(this)
        }
        render() {
            return (
                <div onClick={this.btnAction1}>App comp</div>
                // 每次 render,都会bind一次,可以提前到 constructor 中存储
                <div onClick={this.btnAction2.bind(this)}>App comp</div>
                <div onClick={this.btnAction3(1, 2)}>App comp</div>
                <div onClick={this.btnAction5(1, 2)}>App comp</div>
                <div onClick={this.btnActionBind}>App comp</div>
                <div onClick={(ev) => {
                    // 不推荐这么写,因为 render 每次执行,这里都会重新创建函数以及其作用域,没必要
                    console.log('执行了 :>> ')
                    // 该this为当前组件上下文
                    console.log('this :>> ', this)
                }}>App comp</div>
            )
        }
        btnAction1(ev) {
            // 该this为undefined
            console.log('btnAction1>this :>> ', this) // undefined
        }
        btnAction2(ev) {
            // 该this为当前组件上下文
            console.log('btnAction1>this :>> ', this) // 当前组件
        }
        btnAction3 = (param1, param2, ev) => {
            // 传参数时,事件对象会被放置在最后一个
            console.log('param1 :>> ', param1) // 1
            console.log('param2 :>> ', param2) // 2
            console.log('ev :>> ', ev)
    
            // 箭头函数绑定this为当前组件上下文
            console.log('btnAction1>this :>> ', this) // 当前组件
    
            // react 合成事件
            console.log('ev :>> ', ev)
            console.log('ev :>> ', ev.target) // 绑定事件元素
            console.log('ev :>> ', ev.currentTarget) // 触发元素
    
            // 原生事件
            // 绑定事件元素,点击完成后 nativeEvent 就会被释放掉,设置为 null
            console.log('ev :>> ', ev.nativeEvent.target) 
            // 点击触发元素,通过事件委托在 document 上,冒泡触发事件
            console.log('ev :>> ', ev.nativeEvent.currentTarget) 
        }
        btnAction5 = (param1, param2) => (ev)=> {
            console.log('param1 :>> ', param1) // 1
            console.log('param2 :>> ', param2) // 2
            console.log('ev :>> ', ev)
        }
        btnAction4(ev) {
            // 使用 bind 绑定this为当前组件上下文
            console.log('btnAction1>this :>> ', this) // 当前组件
        }
    }
    

    react 属性类型校验

    • PropTypes 设置组件的数据属性
    • 外部传入或者内部设置的时候进行校验
    // App.js
    import ReactDOM from 'react-dom'
    import React, { Component } from 'react'
    import SonComp from './component/SonComp'
    export default class App extends Component {
        render() {
            return (
                <div>
                    <SonComp plus={this.handlePlus}/>
                </div>
            )
        }
        handlePlus = () => {
            console.log('plus :>> ', 1)
        }
    }
    ReactDOM.render(<App/>, document.querySelector('#root'))
    
    
    // ****************************
    // SonComp.js
    import React, { Component } from 'react'
    import types from 'prop-types'
    export default class SonComp extends Component {
        render() {
            return (
                <div>son comp</div>
            )
        }
    }
    // 设置可接受的数据类型,若不通过校验,则会报错
    SonComp.propTypes = {
        plus: types.func.isRequired
    }
    

    父子组件通讯

    • 父组件在子组件上直接设置值,子组件 props 接收
    • 父组件传递一个函数给子组件,子组件调用函数并传递数据给父组件
    // App.js
    import ReactDOM from 'react-dom'
    import React, { Component } from 'react'
    import SonComp from './component/SonComp'
    export default class App extends Component {
        render() {
            return (
                <div>
                    <SonComp handleAccpet={this.acceptSonData}/>
                </div>
            )
        }
        acceptSonData = (sonData) => {
            console.log('接收到子组件数据 :>> ', sonData)
        }
    }
    ReactDOM.render(<App/>, document.querySelector('#root'))
    // ****************************
    // SonComp.js
    import React, { Component } from 'react'
    export default class SonComp extends Component {
        render() {
            return (
                <div onClick={this.handleSend}>son comp</div>
            )
        }
        handleSend = () => {
            this.props.handleAccpet({ message: '这是子组件传递的数据' })
        }
    }
    

    保持 react 数据不可变原则

    • 不可变数据只需要一次浅比较就可以确定整棵子树是否需要更新
    • merge 视情况可能需要遍历组件树到比较深的层级,在 state 复杂的时候不可变数据会有性能提升
    • 其他好处还包括方便做快照,方便 debug 等等
    import React, { Component } from 'react'
    export default class App extends Component {
        constructor() {
            super()
            this.state = {
                msg: 'msg',
                count: 1,
                obj: {
                    x: 1,
                    y: 2
                },
                arr: [1,2,3]
            }
        }
        render() {
            return (
                <div onClick={this.handleClick}>App</div>
            )
        }
        handleClick = () => {
            // 修改 state 数据,但是要依据数据不可变原则
            this.setState({
                msg: 'other msg',
                count: this.state.count + 1,
                // count: ++this.state.count // 这个违反了不可变原则, ++ 操作直接修改了 count
                obj: {...this.state.obj, y: 3},
                obj: Object.assign({}, this.state.obj, { y: 3}),
                // 增
                arr: [...this.state.arr, 4]
                arr: this.state.arr.concat(4)
                // 删
                arr: this.state.arr.filter((item, index) => index !== 1)
                // 改
                arr: this.state.arr.map((item, index) => index === 1 ? '1' : '0')
            })
        }
    }
    

    react 数据修改的异步与同步

    • react 自身事件中修改数据为异步更新
    • setTimeout、自定义dom事件为同步更新数据
    • setState 第一参数为对象,更新前会进行合并
    • setState 第一参数为返回,更新前不会合并
    import React, { Component } from 'react'
    export default class App extends Component {
        constructor() {
            super()
            this.state = {
                count: 0
            }
        }
        componentDidMount() {
            document.querySelector('#btn').addEventListener('click', () =>{
                console.log('修改数据 :>> ')
                // 同步更新
                this.setState({
                    count: this.state.count + 1
                })
                // 上面为同步更新,所以这里得到 + 1 之后的值为 1
                console.log('this.state.count :>> ', this.state.count)
            })
        }
        render() {
            return (
                <div>{ this.state.count }</div>
                <div onClick={this.handleClick}>点击 + 1</div>
                <div onClick={this.handleMultiClick}>多次修改</div>
                <div id="btn">点击 + 1</div>
            )
        }
        handleClick = () => {
            // 异步更新
            // 点击一次
            this.setState({
                // 这里为异步更新
                count: this.state.count + 1
            })
            // 上面为异步更新,所以这里先执行,得到 + 1 之前的值为 0
            console.log('this.state.count :>> ', this.state.count)
            
            // *********************************
            
            // 同步更新
            // 点击一次
            setTimeout(() => {
                this.setState({
                    count: this.state.count + 1
                })
                // 上面为同步更新,所以这里得到 + 1 之后的值为 1
                console.log('this.state.count :>> ', this.state.count)
            }, 0);
        }
        // 多次异步 setState ,更新前这些操作将会被合并
        handleMultiClick = () => {
             this.setState({
                // 这里为异步更新,多个setState操作将被合并,等价于
                // count: 0 + 1
                count: this.state.count + 1
            }, () => {
                // 修改后的值,相当于 vue 中的 this.$nextTick
                // 全部更新后的回调执行,得到结果 1
                console.log('this.state.count1 :>> ', this.state.count)
            })
    
            this.setState({
                // 这里为异步更新,多个setState操作将被合并,此时 this.state.count 并未变化,等价于
                // count: 0 + 1
                count: this.state.count + 1
            }, () => {
                // 修改后的值,相当于 vue 中的 this.$nextTick
                // 全部更新后的回调执行,得到结果 1
                console.log('this.state.count2 :>> ', this.state.count)
            })
    
            this.setState({
                // 这里为异步更新,多个setState操作将被合并,此时 this.state.count 并未变化,等价于
                // count: 0 + 1
                count: this.state.count + 1
            }, () => {
                // 修改后的值,相当于 vue 中的 this.$nextTick
                // 全部更新后的回调执行,得到结果 1
                console.log('this.state.count3 :>> ', this.state.count)
            })
    
            // 这里同步输出为 0
            console.log('this.state.count4 :>> ', this.state.count)
        }
        // 多次异步 setState ,阻止更新前合并
        handleMultiClick = () => {
             this.setState((preState, props) => {
                // count: 0 + 1
                count: preState + 1
            }, () => {
                // 全部更新后的回调执行,得到结果 3
                console.log('this.state.count1 :>> ', this.state.count)
            })
    
            this.setState((preState, props) => {
                // count: 1 + 1
                count: preState + 1
            }, () => {
                // 全部更新后的回调执行,得到结果 3
                console.log('this.state.count2 :>> ', this.state.count)
            })
    
            this.setState((preState, props) => {
                // count: 2 + 1
                count: preState + 1
            }, () => {
                // 全部更新后的回调执行,得到结果 3
                console.log('this.state.count3 :>> ', this.state.count)
            })
    
            // 这里同步输出为 0
            console.log('this.state.count4 :>> ', this.state.count)
        }
    }
    

    react 生命周期

    挂载

    • constructor()
      • 初始化组件、设置 state
    • static getDerivedStateFromProps(state, props)
      • 相当于 vue computed
      • 获取计算后的 state
      • 返回的数据会被合并到 state
    • render()
      • 提供组件结构
    • componentDidMount()
      • 组件挂载之后调用
      • 可挂载后请求数据,操作 dom
      • 添加事件监听

    更新

    • static getDerivedStateFromProps()
      • 更新阶段重新计算 state
    • shouldComponentUpdate()
      • 根据返回值确实是否需要更新组件
    • render()
      • 计算最小变更,提供新的组件结构
    • getSnapshotBeforeUpdate()
      • 获得更新前的快照
      • 操作的为更新前的dom
    • componentDidUpdate()
      • 更新完毕调用

    销毁

    • componentWillUnmount()
      • 移除事件监听等

    使用 JSX 语法时候需要引入 React

    因为 JSX 编译之后其实会变成 React.createElement()

    import React, { Component } from 'react'
    export default class App extends Component {
        render() {
            return (
                <div>App comp</div>
            )
        }
    }
    // babel-preset-jsx 转换后
    export default class App extends Component {
        render() {
            return React.createElement('div', 'App comp')
        }
    }
    

    函数式组件

    • 2.1. 会接收两个参数,一个是父级传递的 props,一个是 context 上下文,该上下文可能是 Provider 提供的
    • 2.2. 只能操作 props,没有自己的 state,所以称之为无状态组件,也称之为UI组件
    const Comp = (props, context) => {
        return (
            <div>fun comp</div>
        )
    }
    export default Comp
    

    ref 设置

    • react 中不推荐设置字符串形式的 ref,因为每次 render 之后,都会重新设置 ref
    • 而 ref 没有释放会导致内存泄露
    • 16.0之后,使用 createRef 来解决
    • ref 给普通标签设置,获取当前普通标签
    • ref 给组件设置,获取当前组件对象

    设置 ref 的三种方式

    import React, { createRef } from 'react'
    constructor() {
        // 第三种
        this.refName = createRef()
    }
    return (
        // 第一种、不推荐
        <div ref="refName"></div> 
        // 第二种、函数形式,即可在当前组件使用 this.refName 获取当前元素,element 即是当前元素
        <div ref={(element) => { this.refName = element}}></div> 
        // 第三种、将ref 设置为组件变量 this.refName
        // 而这个 this.refName = createRef() 其值为: { current: element }
        // 取值 this.refName.current === element
        <div ref={this.refName}"></div>
    )
    

    ref 转发

    • ref 设置在子组件上,但是该 ref 可以不是获取当前组件对象
    • 可以子组件内部自己设置 ref 所指定的元素或者对象
    import React, { createRef } from 'react'
    constructor() {
        // 第三种
        this.refName = createRef()
    }
    componentDidMount() {
        console.log('refName', this.refName) // 这里为 SonComp 中的某个元素
    }
    return (
        <SonComp ref={this.refName} />
    )
    
    // ********************************
    // SonComp.js
    // 在 SonComp 中,将 ref 转发到自身组件的某个元素上
    // 这样,父组件即可获得自身组件的某个元素
    
    // 函数式组件接收 ref
    export default React.forwardRef((props, ref) => { 
        return (
            <div ref={ref}></div>
            // 或者
            <OtherComp ref={ref}/>
        )
    })
    // 类组件接收 ref
    export default React.forwardRef((props, ref) => {
        class AcceptComp extends Component {
            render() {
                return (
                    <div ref={ref}></div>
                    // 或者
                    <OtherComp ref={ref}/>
                )
            }
        }
        return <AcceptComp />
    })
    

    页面内部的子组件脱离父组件渲染

    • 子组件脱离父组件在父组件外部渲染
    • 但是子组件依然可以使用父组件的数组,可以获取父组件的上下文
    // 1、html 上有 id 为 model-root 的 div 元素
    // 2、Model 渲染时候可以在 model-root 内部渲染
    // 3、Model 可以使用当前组件上下文和数据
    export default class App extends Component {
        constructor() {
            this.state = {
                x: 1
            }
        }
        render() {
            return (
                <div>
                    // 这里 Model 不会渲染在这个位置
                    // 而是渲染在外部指定的元素标签底下
                    <Model data={this.state} />
                </div>
            )
        }
    }
    
    // ***********************
    // Model.js
    const modelRoot = document.querySelector('#model-root')
    export default class Model extends Component {
        constructor(props) {
            super(props)
            this.el = document.createElement('div')
        }
        componentDidMount() {
            modelRoot.appendChild(this.el)
        }
        componentWillUnmount() {
            modelRoot.removeChild(this.el)
        }
        render() {
            // 传送门,将 Model 组件的内容 this.props.children 放在新创建的 div 标签中, 即 this.el
            // 而 this.el 在组件挂载的时候,已经被 appendChild 到指定的外部元素中了
            // 所以当前整个组件都在外部了,父组件不会渲染当前组件进行占位
            return ReactDOM.cratePortal(
                this.props.children,
                this.el
            )
        }
    }
    
    
    

    组件间通讯

    • 定义共享上下文 StoreContext
    • 使用 react 提供的 createContext 创建一个共享上下文 StoreContext
    • 使用该上下文 StoreContext.Provider 包裹一个父组件
    • createContext 上的数据变化会导致其包裹的组件都重新渲染,所以建议保存不经常变化的数据,如背景色、主题风格、国际化等
    • 经常变化的数据建议使用 redux 来管理共享数据
    // StoreContext.js
    import { createContext } from 'react'
    const storeContext = createContext(这里可以设置初始值)
    export default storeContext
    
    // **********************************
    
    // App.js
    import StoreContext from './context/StoreContext'
    export default class App extends Component {
        render() {
            return (
                // 提供数据
                <StoreContext.Provider data={x: 1}>
                    <div>
                        <SonComp/>
                    </div>
                </StoreContext.Provider>
            )
        }
    }
    
    • 第一种方式
      • 使用子组件.contextType = StoreContext ,就可以从 this.context 获取数据
    // SonComp.js
    // 第一种 contextType(推荐类组件使用,不用使用 Consumer 冗长)
    import StoreContext from './context/StoreContext'
    export default class SonComp extends Component {
        constructor(props, context) {
            super()
            // 这个 context 即是 StoreContext
            // 当前组件可以拿到父组件上使用 StoreContext 共享的数据
        }
        render() {
            // 这里取 context 的时候,会去寻找当前组件的 contextType
            // 发现为 contextType 为 StoreContext ,此时会从当前组件树往上去查找是否有
            // StoreContext 类型的 Provider
            console.log('this.context :>> ', this.context)
            return (
                <div>son comp</div>
            )
        }
    }
    // 设置可获取的上下文
    SonComp.contextType = StoreContext
    
    • 第二种方式
      • 子孙组件可以使用 Consumer 获取到设置在该上下文上的数据
    // SonComp.js
    // 第二种 Consumer (推荐函数式组件使用,可以不使用 this)
    import StoreContext from './context/StoreContext'
    export default class SonComp extends Component {
        render() {
            return (
                <div>
                <StoreContext.Consumer>
                {
                    (data) => {
                        return (
                            <div>accept data</div>
                        )
                    }
                }
                </StoreContext.Consumer>
                </div>
            )
        }
    }
    
    
    • 第三种方式
      • vue 种的 eventbus 方式
      • 或者 pubsub-js(因为 vue 相对来说太大了)
    import PubSub from 'pubsub-js'
    // SonComp.js
    export default class SonComp extends Component {
        render() {
            return (
                <div onClick={this.handleClick}>SonComp</div>
            )
        }
        handleClick = () => {
            // 触发 add 事件,并传入一个参数值为 1
            PubSub.publish('add', 1)
        }
    }
    // ******************************
    // OtherComp.js
    import PubSub from 'pubsub-js'
    export default class OtherComp extends Component {
        constructor() {
            super()
            this.state = {
                a: 1,
                b: 2
            }
        }
        render() {
            return (
                <div onClick={this.handleClick}>OtherComp</div>
            )
        }
        componentDidMount() {
            this.reference = PubSub.subscribe('add', (eventName, ...rest) => {
                console.log('触发了 add :>> 接收到数据', rest)
                // 这是引用了 this,组件销毁是,需要移除 PubSub 事件监听
                this.setState({
                    c: 3
                })
            })
        }
        componentWillUnmount() {
            // 记得移除,否则可能造成内存泄露
            PubSub.unsubscribe(this.reference)
        }
    }
    

    异常捕获

    • getDerivedStateFromError、 componentDidCatch 只可以捕获子孙组件异常,自身组件异常无法捕获
    • 可以在根组件设置捕获函数,捕获其所有子孙组件的错误,统一设置错误发生时候的逻辑
    • 同时将错误信息上传到日志服务中心,以便分析异常情况
    export default class App extends Component {
        constructor() {
            super()
            this.state = {
                x: 0
            }
        }
        render() {
            return (
                <div>
                    // 子孙组件报错会被捕获
                    <SonComp/>
                </div>
            )
        }
        // 两个方法都是异常捕获的方法,不可共存
        // 只需要实现其中一个即可
        static getDerivedStateFromError(error) {
            // 不能访问 this,this 为 undefined
            console.log('获取子孙组件异常', error)
            // 可通过返回值的方式,合并 this.state 对象
            return {
                x: 1
            }
        }
        componentDidCatch(error, stack) {
            // 可调用 this
            console.log('获取子孙组件异常', error, stack)
            // 可直接修改 this.state
            this.setState({
                x: 1
            })
        }
    }
    

    render 的 return 格式

    • 不能 return 多个对象
    • 可以 return 数组
    • 必须包裹一个最外层
    • 可以使用 <Fragment></Fragment> 包裹元素,但是最终并不会渲染 Fragment
    • 可以使用 <></> 包裹元素,<></> 是 Fragment 的简写
    import { Fragment } from 'react'
    render() {
        return (
            // 不可以
            <div>1</div>
            <div>2</div>
            <div>3</div>
    
            // 可以---包裹一个标签
            <div>
                <div>1</div>
                <div>2</div>
                <div>3</div>
            </div>
    
            // 可以---数组渲染
            [
                <div>1</div>,
                <div>2</div>,
                <div>3</div>
            ]
    
            // 可以---Fragment
            <React.Fragment>
                <div>1</div>
                <div>2</div>
                <div>3</div>
            </React.Fragment>
    
            // 可以---空标签<></>,但是不推荐,因为浏览器可能不支持或者渲染异常
            <>
                <div>1</div>
                <div>2</div>
                <div>3</div>
            </>
        )
    }
    

    异步组件

    • Suspense、lazy 实现异步组件,不用不加载,使用到才加载
    import React, { Component, Suspense, lazy } from 'react'
    // 使用 lazy 异步加载
    const AsyncComp = lazy(() => import('./component/AsyncComp'))
    export default class App extends Component {
        constructor() {
            super()
            this.state = {
                show: false
            }
        }
        render() {
            const { show } = this.state
            return (
                <div>
                    // 配合使用 Suspense 才能使用异步组件
                    // 在加载异步js同时,需要使用 fallback 作为临时提示
                    // 加载完成后关闭提示,展示异步组件逻辑
                    <Suspense fallback={<Loading/>}>
                        { show && <AsyncComp />}
                    </Suspense>
                </div>
            )
        }
    }
    

    immutable.js 设置不可变对象

    • react 中为了性能优化,需要保持 state 的值不变,可以使用 immutable 来实现
    • immutable 内部提供的所有数据类型,对其数据进行任意操作
    • 操作得到的结果是修改后的值,且修改后的值是一个新对象,原来对象并没有发生变化

    备注:我觉得为了实现这个不可变,引入一个新库,并且这个新库还有自己的操作api,实在是令人恶心

    import { Map } from 'immutable'
    const originObj = {a:1, b: 2, c: 3}
    const immutableObj = Map(originObj)
    const map1 = immutableObj.set({ a: 2 }) // map1 => { a:2, b: 2, c: 3 }
    immutableObj.get('a') // 1
    map1.get('a') // 2
    
    得到修改后的全新的对象 map1
    但是 immutableObj 不会改变 
    
    • 数据类型对应
    • 不同数据类型都有自己的增删改查Api,需要去官网查询
    Map => {}
    List => []
    

    IDE 报错解决

    1、

    提示找不到 react 声明或者

    JSX 元素隐式具有类型 "any",因为不存在接口 "JSX.IntrinsicElements"
    等等

    解决:

    安装 yarn add @types/react

    都读到最后了、留下个建议如何
  • 相关阅读:
    2020软件工程作业04
    2020软件工程作业03
    一个我一定会完成的web学习项目
    2020软件工程作业02
    2020软件工程作业01
    423团队选题报告
    计算与软件工程作业五
    计算与软件工程第四次作业
    计算与软件工程第三次作业
    计算与软件工程作业二
  • 原文地址:https://www.cnblogs.com/linjunfu/p/14616570.html
Copyright © 2011-2022 走看看