React 入手篇 - 实战

32 篇文章 0 订阅
3 篇文章 0 订阅

React

在这里插入图片描述

此文章类写法,函数写法参考其他文章

React框架有知识或者概念有很多和Vue类似,
此文章没有写详细知识点的描述,主要以语法配合demo的实际应用,
更多细节和知识点请参考官方手册。

概述

用于构建用户界面的JavaScript库(只关注View)

由 Facebook 开源

(1)	英文官网: https://reactjs.org/2)中文官网: https://doc.react-china.org/

特点

1、Declarative(声明式编码)
以声明式编写 UI,可以让你的代码更加可靠,且方便调试。


2、Component-Based(组件化编码)
组件逻辑使用 JavaScript 编写而非模版,因此你可以轻松地在应用中传递数据,并使得状态与 DOM 分离


3、Learn Once,Write Anywhere(支持客户端与服务器渲染)
React 还可以使用 Node 进行服务器渲染,或使用 React Native 开发原生移动应用。


4、高效


5、单项数据流

依赖库

1、react.js (React的核心库)

2、react-dom.js (提供操作 DOM 的react扩展库)

3、babel.min.js(解析JSX语法代码转为纯JS语法代码的库)

测试

<body>
    <div id="test"></div>

    <script src="react.development.js"></script>
    <script src="react-dom.development.js"></script>
    <script src="babel.min.js"></script>
    <script type="text/babel">
        // 创建虚拟Dom元素对象
        var vDom = <h1>Hello</h1>
        // 将虚拟Dom渲染到页面真实Dom容器中
        ReactDOM.render(vDom,document.getElementById('test'))
    </script>
</body>

JSX

JSX是一种JavaScript的语法扩展,运用于React架构中,其格式比较像是模版语言,但事实上完全是在JavaScript内部实现的。

元素是构成React应用的最小单位,JSX就是用来声明React当中的元素,React使用JSX来描述用户界面。

作用: 用来创建react虚拟DOM(元素)对象

a.	var ele = <h1>Hello JSX!</h1>
b.	注意1: 它不是字符串, 也不是HTML/XML标签
c.	注意2: 它最终产生的就是一个JS对象



基本语法规则

a.	遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析
b.	遇到以 { 开头的代码,以JS语法解析: 标签中的js代码必须用{ }包含


例如,以下代码:

<body>
    <div id="container"></div>

    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>

    <script type="text/babel">
        const myId = 'test'
        const content = '我是内容'

        // 创建虚拟dom
        let element = <h1 id={myId}>{content}</h1>

        // 渲染dom
        ReactDOM.render(element,document.getElementById('container'))
    </script>
</body>
babel.js的作用

a.	浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
b.	只要用了JSX,都要加上type="text/babel", 声明需要babel来处理

渲染虚拟DOM

1)	语法:  ReactDOM.render(virtualDOM, containerDOM) 
2)	作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
3)	参数说明
a.	参数一: 纯js或jsx创建的虚拟dom对象
b.	参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)


建虚拟DOM的2种方式

(1)	纯JS(一般不用)
React.createElement('h1',  {id:'myTitle'},  title)

(2)	JSX:
<h1 id='myTitle'>{title}</h1>

创建列表(demo)

<body>
    <div id="container"></div>
    
    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>

    <script type='text/babel'>
        const data = ['first','second','third','fourth']

        // 创建虚拟DOM
        let element = (
            <ul>
                {
                    data.map((name,index) => <li key={index}>{name}</li>)
                }
            </ul>
            )

        // 渲染 DOM
        ReactDOM.render(element,document.getElementById('container'))
    </script>
</body>

组件

三大属性

1、state

state是组件对象最重要的属性, 值是对象(可以包含多个数据)
组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)



2: props

每个组件对象都会有props(properties的简写)属性
组件标签的所有属性都保存在props中

作用:
1)	通过标签属性从组件外向组件内传递变化的数据
2)	注意: 组件内部不要修改props数据


3: refs

1)	组件内的标签都可以定义ref属性来标识自己

a.	<input type="text" ref={input => this.msgInput = input}/>
b.	回调函数在组件初始化渲染完或卸载时自动调用
2)	在组件中可以通过this.msgInput来得到对应的真实DOM元素
3)	作用: 通过ref获取组件内容特定标签对象, 进行读取其相关数据



事件处理:
1)	通过onXxx属性指定组件的事件处理函数(注意大小写)
a.	React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
b.	React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)

语法

定义组件(2种方式)1) 创建组件

/*方式1: 工厂函数组件(简单组件)*/
function MyComponent () {
  return <h2>工厂函数组件(简单组件)</h2>
}

/*方式2:  ES6类组件(复杂组件)*/
class MyComponent2 extends React.Component {
  render () {
    console.log(this) // MyComponent2的实例对象
    return <h2>ES6类组件(复杂组件)</h2>
  }
}2)	渲染组件标签
ReactDOM.render(<MyComponent />, document.getElementById('example1'))





例如以下代码:

<body>
    <div id="container"></div>
    <div id="box"></div>
    
    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>

    <script type='text/babel'>
        // 第一种方式(定义简单组件)
        function MyComponent() {
            return <h1>我是简单的组件</h1>
        }

        // ES6 类组件(复杂组件)
        class MyClassComponent extends React.Component{
            render(){
                return <h1>我是类定义的复杂组件</h1>
            }
        }

        ReactDOM.render(<MyClassComponent /> , document.getElementById('container'))
        ReactDOM.render(<MyComponent />, document.getElementById('box'))

    </script>
</body>

点击按钮(state属性的应用)

<body>
    <div id="container"></div>

    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>

    <script type='text/babel'>

        // 点击like切换组件
        class LikeComponent extends React.Component {

            constructor(props) {
                super(props)
                // 初始化状态
                this.state = {
                    isLike: false
                }

                // 将新增方法的this强制绑定为组件对象,这样不会出现this丢失
                this.handleClick = this.handleClick.bind(this)
            }

            handleClick() {

                console.log(this)
                const isLike = !this.state.isLike

                //更新状态
                this.setState({ isLike })
            }

            // 重写组件类的方法
            render() {
                // 读取状态
                const { isLike } = this.state


                return <h2 onClick={this.handleClick}>{isLike ? '你喜欢我' : '我不喜欢'}</h2>
            }
        }

        ReactDOM.render(<LikeComponent />, document.getElementById('container'))

    </script>
</body>

组件传参(props属性的应用)

以下代码,设置了组件的默认参数,还有参数的类型和是否是必要传参

新增了prop-types.js文件,这个文件作用是更方便的去设置参数的类型和必要性

代码如下:

<body>
    <div id="container"></div>
    <div id="box"></div>
    <div id="box2"></div>
    <div id="box3"></div>

    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>
    <script src="./prop-types.js"></script>

    <script type='text/babel'>
        // 创建Person组件,第一种方法
        function Person(props) {
            return (
                <ul>
                    <li>姓名:{props.name}</li>
                    <li>性别:{props.sex}</li>
                    <li>年龄:{props.age}</li>
                </ul>
            )
        }

        // 默认数据(默认性别为男,年龄18)-----指定默认值
        Person.defaultProps = {
            sex: '男',
            age: 18
        }

        // 指定属性值类型和必要性(isRequired代表必须传参,否则报错)
        Person.propTypes = {
            name : PropTypes.string.isRequired,
            age : PropTypes.number
        }


        // 参数数据
        const jine = {
            name: 'jine',
            age: 22,
            sex: '男'
        }

        // 参数数据
        const ren = {
            name: 'ren',
            age: 18,
            sex: '男'
        }

        // 参数数据,只传姓名参数,其它参数由组件默认提供
        const onlyName = {
            name: 'go'
        }

        // 创建Person组件,第二种方法
        class PersonClass extends React.Component {
            render() {
                return (
                    <ul>
                        <li>姓名:{this.props.name}</li>
                        <li>性别:{this.props.sex}</li>
                        <li>年龄:{this.props.age}</li>
                    </ul>
                )
            }
        }

        // 渲染DOM,原始传参
        ReactDOM.render(<Person name={jine.name} age={jine.age} sex={jine.sex} />, document.getElementById('box'))

        // 渲染DOM,ES6扩展运算符传参
        ReactDOM.render(<Person {...jine} />, document.getElementById('container'))

        // 渲染DOM,ES6扩展运算符传参(只传姓名参数,其他参数由组件默认提供)
        ReactDOM.render(<Person {...onlyName} />, document.getElementById('box3'))

        // 渲染DOM,ES6扩展运算符传参
        ReactDOM.render(<PersonClass {...ren} />, document.getElementById('box2'))

    </script>
</body>

输入框(refs属性和事件处理)

refs可以当做定位元素用(旧版本)
input => this.input = input (这是以下代码中新版的支持,也是官方建议写法)

<body>
    <div id="container"></div>
    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>
    <script type='text/babel'>

        // 定义组件
        class MyComponent extends React.Component {
            constructor(props) {
                super(props)

                this.showInput = this.showInput.bind(this)
            }

            showInput() {
                const input = this.refs.content
                alert(input.value)
                alert(this.input.value)
            }

            handleBlur(event) {
                alert(event.target.value)
            }



            render() {
                return (
                    <div>
                        <input type="text" ref='content' />
                        <input type="text" ref={input => this.input = input} />
                        <button onClick={this.showInput} >输入</button>
                        <button onClick={this.showInput} >输入</button>
                        <input type="text" onBlur={this.handleBlur} placeholder='失去焦点提示内容' />
                    </div>
                )
            }
        }



        // 渲染组件
        ReactDOM.render(<MyComponent />, document.getElementById('container'))
    </script>
</body>

Todo(组件应用综合demo)

<body>
    <div id='container'></div>

    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>
    <script src="./prop-types.js"></script>

    <script type='text/babel'>

        // 定义父组件
        class App extends React.Component {
            constructor(props) {
                super(props)
                this.state = {
                    todos: ['吃饭', '睡觉', '打代码']
                }
                this.addTodo = this.addTodo.bind(this)
            }

            addTodo(todo) {
                const { todos } = this.state
                todos.unshift(todo)
                this.setState({ todos })
            }

            render() {
                const { todos } = this.state
                return (
                    <div>
                        <h1>ToDo List</h1>
                        <Add count={todos.length} addTodo={this.addTodo} />
                        <List todos={todos} />
                    </div>
                )
            }
        }

        // 定义子组件,Add
        class Add extends React.Component {

            constructor(props) {
                super(props)
                this.add = this.add.bind(this)
            }

            add() {

                // 读取数据
                const todo = this.input.value.trim()

                // 检查合法性
                if (!todo) return
                this.props.addTodo(todo)
                // 清楚输入
                this.input.value = ''
            }

            render() {
                return (
                    <div>
                        <input type="text" name="" id="" ref={input => this.input = input} />
                        <button onClick={this.add}>add #{this.props.count + 1}</button>
                    </div>
                )
            }
        }

        // 定义子组件,list
        class List extends React.Component {
            render() {
                return (
                    <ul>
                        {
                            this.props.todos.map((todo, index) => {
                                return <li key={index}>{todo}</li>
                            })
                        }
                    </ul>
                )
            }
        }

        Add.propTypes = {
            count: PropTypes.number.isRequired,
            addTodo: PropTypes.func.isRequired
        }

        List.propTypes = {
            todos: PropTypes.array.isRequired
        }

        // 渲染组件
        ReactDOM.render(<App />, document.getElementById('container'))
    </script>
</body>

表单提交(受控组件与非受控组件应用)

受控组件: 表单项输入数据能自动收集成状态(读的是state)
非受控组件: 需要时才手动读取表单输入框中的数据
<body>
    <div id="container"></div>

    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>

    <script type='text/babel'>
        // 定义表单组件
        class MyForm extends React.Component {
            constructor(props) {
                super(props)
                this.state = {
                    pwd: ''
                }

                this.handleSub = this.handleSub.bind(this)
                this.handleChange = this.handleChange.bind(this)
            }

            // 提交处理
            handleSub(event) {
                // 获取用户姓名(非受控组件)
                const username = this.username.value
                // 获取密码(受控组件)
                const { pwd } = this.state
                alert(`提交的用户为:${username},密码为:${pwd}`)
                // 阻止默认提交行为
                event.preventDefault();

            }

            handleChange(event) {

                const pwd = event.target.value
                // 将用户输入的密码添加到state中
                this.setState({ pwd })

            }


            render() {
                return (
                    <form action="#">
                        用户名:
                        <input type="text" ref={name => this.username = name} />
                        密码:
                        <input type="password" onChange={this.handleChange} />
                        <input type="submit" value='提交' onClick={this.handleSub} />
                    </form>
                )
            }

        }

        // 渲染 DOM
        ReactDOM.render(<MyForm />, document.getElementById('container'))
    </script>
</body>

组件生命周期

React 16 之后有三个生命周期被废弃(但并未删除)

componentWillMount
componentWillReceiveProps
componentWillUpdate

img

目前React 16.8 +的生命周期分为三个阶段,分别是挂载阶段、更新阶段、卸载阶段。
 

1、挂载阶段:

constructor: 构造函数,最先被执行,我们通常在构造函数里初始化state对象或者给自定义方法绑定this


getDerivedStateFromProps: static getDerivedStateFromProps(nextProps, prevState),这是个静态方法,当我们接收到新的属性想去修改我们state,可以使用getDerivedStateFromProps

render: render函数是纯函数,只返回需要渲染的东西,不应该包含其它的业务逻辑,可以返回原生的DOM、React组件、Fragment、Portals、字符串和数字、Boolean和null等内容

componentDidMount: 组件装载之后调用,此时我们可以获取到DOM节点并操作,比如对canvas,svg的操作,服务器请求,订阅都可以写在这个里面,但是记得在componentWillUnmount中取消订阅
 


2、更新阶段:
getDerivedStateFromProps: 此方法在更新个挂载阶段都可能会调用

shouldComponentUpdate: shouldComponentUpdate(nextProps, nextState),有两个参数nextProps和nextState,表示新的属性和变化之后的state,返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true,我们通常利用此生命周期来优化React程序性能

render: 更新阶段也会触发此生命周期

getSnapshotBeforeUpdate: getSnapshotBeforeUpdate(prevProps, prevState),这个方法在render之后,componentDidUpdate之前调用,有两个参数prevProps和prevState,表示之前的属性和之前的state,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate搭配使用

componentDidUpdate: componentDidUpdate(prevProps, prevState, snapshot),该方法在getSnapshotBeforeUpdate方法之后被调用,有三个参数prevProps,prevState,snapshot,表示之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate返回的,如果触发某些回调函数时需要用到 DOM 元素的状态,则将对比或计算的过程迁移至 getSnapshotBeforeUpdate,然后在 componentDidUpdate 中统一触发回调或更新状态。
 


3、卸载阶段:
componentWillUnmount: 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除定时器,取消网络请求或清除在 componentDidMount() 中创建的订阅,清理无效的DOM元素等垃圾清理工作。
 

异常处理:

static getDerivedStateFromError: 此生命周期会在渲染阶段后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state。

componentDidCatch:此生命周期在后代组件抛出错误后被调用。 它接收两个参数:1. error —— 抛出的错误。2. info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。componentDidCatch 会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况。

上张图的生命周期细节坑比较多,建议先会使用这张图的生命周期:

image-20201115150230940

计时器(生命周期应用)

<body>
    <div id="container"></div>

    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>
    <script type="text/babel">

        class Life extends React.Component {
            constructor(props) {
                super(props)

                // 初始化状态
                this.state = {
                    opacity: 1
                }

                this.componentWillUnmount = this.componentWillUnmount.bind(this)
            }

            componentDidMount() {
                this.inter = setInterval(() => {
                    console.log('计时器...')
                    console.log(this, 'aa')
                    let { opacity } = this.state
                    opacity -= 0.1
                    if (opacity < 0) {
                        opacity = 1
                    }

                    this.setState({ opacity })
                }, 100)
            }

            componentWillUnmount() {
                clearInterval(this.inter)
            }

            render() {
                const { opacity } = this.state
                return (
                    <div>
                        <h2 style={{ opacity: opacity }}>{this.props.msg}</h2>
                        <button onClick={this.componentWillUnmount}>暂停</button>
                    </div>
                )
            }


        }

        ReactDOM.render(<Life msg='我是React' />, document.getElementById('container'))

    </script>
</body>

虚拟DOM与DOM Diff算法

基本原理图,如下:

具体diff算法实现,可以参考我其他文章

React 脚手架

概述

(1)	xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
    a.	包含了所有需要的配置
    b.	指定好了所有的依赖
    c.	可以直接安装/编译/运行一个简单效果
    
(2)	react提供了一个用于创建react项目的脚手架库: create-react-app(这的项目采用了官方脚手架帮助学习-因可以兼容低版本。企业应用项目建议用新的脚手架 next.js来创建-兼容版本为16以上,性能相对更好)

(3)	项目的整体技术架构为:  react + webpack + es6 + eslint

(4)	使用脚手架开发的项目的特点: 模块化, 组件化, 工程化

安装并使用

npm install -g create-react-app

create-react-app hello-react

cd hello-react

npm start

评论(demo)

访问链接:

异步请求

axios(结合react)

<body>
    <div id="container"></div>

    <script src="./react.development.js"></script>
    <script src="./react-dom.development.js"></script>
    <script src="./babel.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.js"></script>

    <script type='text/babel'>
        class AsyncRepo extends React.Component {
            state = {
                repoName: '',
                repoUrl: ''
            }


            componentDidMount() {
                const url = 'https://api.github.com/search/repositories?q=re&sort=stars'
                axios.get(url).then(res => {
                    // 得到数据
                    console.log(res)
                    const { name, html_url } = res.data.items[0]

                    // 更新状态
                    this.setState({ repoName: name, repoUrl: html_url })
                })
            }

            render() {
                const { repoName, repoUrl } = this.state

                if (!repoName) {
                    return <h2>LOADING...</h2>
                } else {
                    return <h2>Most star repo is <a href={repoUrl}>{repoName}</a></h2>
                }
            }
        }

        ReactDOM.render(<AsyncRepo />, document.getElementById('container'))
    </script>
</body>

fetch(结合react)

 fetch(url).then(res=>{
                    return res.json()
                }).then(data =>{
                    const { name, html_url } = data.items[0]

                    // 更新状态
                    this.setState({ repoName: name, repoUrl: html_url })
                })
            }

组件通信

props 传递

1)	共同的数据放在父组件上, 特有的数据放在自己组件内部(state)
2)	通过props可以传递一般数据和函数数据, 只能一层一层传递
3)	一般数据-->父组件传递数据给子组件-->子组件读取数据
4)	函数数据-->子组件传递数据给父组件-->子组件调用函数


缺点:
若兄弟组件或祖孙组件,就不能直接传,还要借用第三个中间组件来一层层传递
1)	共同的数据放在父组件上, 特有的数据放在自己组件内部(state)
2)	通过props可以传递一般数据和函数数据, 只能一层一层传递
3)	一般数据-->父组件传递数据给子组件-->子组件读取数据
4)	函数数据-->子组件传递数据给父组件-->子组件调用函数


缺点:
若兄弟组件或祖孙组件,就不能直接传,还要借用第三个中间组件来一层层传递

使用消息订阅(subscribe)-发布(publish)机制

1)	工具库: PubSubJS

2)	下载: npm install pubsub-js --save

3)	使用: 
	  import PubSub from 'pubsub-js' //引入
	  PubSub.subscribe('delete', function(data){ }); //订阅
	  PubSub.publish('delete', data) //发布消息


这样可以实现任意组件通信

redux

redux也可以实现任意组件通信,后面单独写redux内容

路由(react-router4)

概述

1)	react的一个插件库
2)	专门用来实现一个SPA应用
3)	基于react的项目基本都会用到此库

SPA

1)	单页Web应用(single page web application,SPA2)	整个应用只有一个完整的页面
3)	点击页面中的链接不会刷新页面, 本身也不会向服务器发请求
4)	当点击路由链接时(相当跳转到了子组件), 只会做页面的局部更新
5)	组件内容数据都需要通过ajax请求获取, 并在前端异步展现

路由的理解

1)	什么是路由?
a.	一个路由就是一个映射关系(key:value)
b.	key为路由路径, value可能是function/component


2)	路由分类
a.	后台路由: node服务器端路由, value是function, 用来处理客户端提交的请求并返回一个响应数据
b.	前台路由: 浏览器端路由, value是component, 当请求的是路由path时, 浏览器端前没有发送http请求, 但界面会更新显示对应的组件 


3)	后台路由
a.	注册路由: router.get(path, function(req, res))
b.	当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
                     
                     
4)		前端路由
a.	注册路由: <Route path="/about" component={About}>
b.	当浏览器的hash变为#about时, 当前路由组件就会变为About组件

路由实现

1)	history库
a.	网址: https://github.com/ReactTraining/history
b.	管理浏览器会话历史(history)的工具库
c.	包装的是原生BOM中window.history和window.location.hash


2)	history API
a.	History.createBrowserHistory(): 得到封装window.history的管理对象
b.	History.createHashHistory(): 得到封装window.location.hash的管理对象
c.	history.push(): 添加一个新的历史记录
d.	history.replace(): 用一个新的历史记录替换当前的记录
e.	history.goBack(): 回退到上一个历史记录
f.	history.goForword(): 前进到下一个历史记录
g.	history.listen(function(location){}): 监视历史记录的变化

react-router相关API

1. 组件
1)	<BrowserRouter> (使用HTML5的history API(pushState, replaceState和popState),让页面的UIURL同步。)
2)	<HashRouter>  (使用的是URL的hash部分(即window.location.hash))
3)	<Route>
4)	<Redirect>
5)	<Link>
6)	<NavLink>
7)	<Switch>
    
    
2. 其它
1)	history对象
2)	match对象
3)	withRouter函数

安装

1)	下载react-router: npm install --save react-router-dom

2)	引入bootstrap.css: <link rel="stylesheet" href="/css/bootstrap.css">

使用

关键代码如下:

// 导入路由库
import {Route, Switch, Redirect} from 'react-router-dom'


 {/*导航路由链接*/}
              <MyNavLink className="list-group-item" to='/about' >About</MyNavLink>
              <MyNavLink className="list-group-item" to='/home'>Home</MyNavLink>


{/*可切换的路由组件,渲染跳转*/}
                <Switch>
                  <Route path='/about' component={About} />
                  <Route path='/home' component={Home} />
                   // 重定向
                  <Redirect to='/about' />
                </Switch>

index.js 文件下的配置

import React from 'react'
import ReactDOM from 'react-dom'
import {BrowserRouter, HashRouter} from 'react-router-dom'
import App from './components/app'

import './index.css'

ReactDOM.render(
  (
    <BrowserRouter>
      <App />
    </BrowserRouter>
    /*<HashRouter>
      <App />
    </HashRouter>*/
  ),

  document.getElementById('root')
)

React UI 组件库

常用库

material-ui (国外)

官网:http://www.material-ui.com/#/

gitHub: https://github.com/callemall/material-ui

2、ant-design(国内蚂蚁金服)

PC 官网:https://ant.design/index-cn

移动官网:https://mobile.ant.design/index-cn

Github:https://github.com/ant-design/ant-design/

Github:https://github.com/ant-design/ant-design-mobile/

安装:

npm install antd --save

组件按需打包(ant-design)

有的组件有自己的css样式和js特效,那么原来的做法是按照一键导入,需要import 一个总的css包或js包,但这样有点浪费资源。所以可以进行如下配置,实现自动用哪个组件按需要导入相应的css或js包

1、下载依赖包

yarn add antd

yarn add @craco/craco

yarn add craco-less


'请注意':
下面这个依赖包在2.0版本后已经废弃
yarn add react-app-rewired customize-cra babel-plugin-import

若非想要安装这个依赖包,只能是降低自己的 react-app-rewired 版本(不建议这样做)
// 从 2.0版本开始 react-app-rewired 很多东西被废弃了,这里采用官方推荐的craco

2、修改默认配置(package.json文件)

  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test"
  }

3、创建文件(config-overrides.js文件)

const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: { '@primary-color': '#1DA57A' },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

4、在src文件夹下创建App.less文件

@import '~antd/dist/antd.less';

5、使用相应组件(如按钮)

import React, { Component } from 'react'
import { Button } from 'antd';

// 导入配置好的less文件
import './App.less';

// 这样就不用导入这个CSS总文件
//import 'antd/dist/antd.css';

export default class App extends Component {
    state = {
      loadings: [],
    };
  
    enterLoading = index => {
      this.setState(({ loadings }) => {
        const newLoadings = [...loadings];
        newLoadings[index] = true;
  
        return {
          loadings: newLoadings,
        };
      });
      setTimeout(() => {
        this.setState(({ loadings }) => {
          const newLoadings = [...loadings];
          newLoadings[index] = false;
  
          return {
            loadings: newLoadings,
          };
        });
      }, 6000);
    };
  
    render() {
      const { loadings } = this.state;
      return (
        <>
          <Button type="primary" loading={loadings[0]} onClick={() => this.enterLoading(0)}>
            Click me!
          </Button>
        </>
      );
    }
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值