zoukankan      html  css  js  c++  java
  • 前端(八):react入门

      React 特点:声明式设计、虚拟DOM、JSX、组件、数据驱动。

    一、环境搭建

      1.安装npm、cnpm

    # 安装node.js 从而安装npm,它会在当前用户家目录下生成node_moudules文件夹,来对npm安装的全局第三方包进行管理
    brew install node
    # npm安装cnpm,因为npm默认的库下载速度太慢,所以建议使用cnpm指定淘宝库 npm
    install -g cnpm --registry=https://registry.npm.taobao.org npm config set registry https://registry.npm.taobao.org # 测试 cnpm install express -g

      2.安装react全家桶

    # 安装create-react-app
    cnpm install create-react-app -g
    # 利用create-react-app 来创建一个项目
    create-react-app 项目名称 # 假设这里的项目名称是my-app
    # 进入项目文件夹
    cd my-app
    # 生成配置文件
    # cnpm run eject # 生成scripts文件夹和config文件夹,cnpm
    # 启动服务
    cnpm start # 它相当于执行 scrpits/starts.js,这个已经在package.json中配置好了

      3.文件目录结构

    my-app
        - config                        # 项目默认配置文件,由npm run eject生成
        - .gitignore                    # git配置
        - node_modules                  # 本地第三方安装包
        - package.json                  # npm项目配置,里面记录了项目的名字、版本、依赖包、和自定义配置 
        - package-lock.json
        -  public                       # 公共资源
           - index.html                # 静态页面
        - README.md            
        -  scripts                      # 配置pacakage.json中的"scripts"定义的命令
            - build.js                  # build命令,可由npm build执行,生成静态文件用于迁移到生产环境
            - start.js                  # start命令
            - test.js                
        -  src
            - App.css                   # 创建项目时自动生成的css样式,没用
            - App.js                    # react组件
            - App.test.js
            - index.css                 # 入口文件的样式
            - index.js                  # 入口文件
            - log.svg
            - registerServiceWorker.js

      项目启动时,会加载public下的index.html文件,并进而执行index.js,从而完成整个页面的渲染。

    二、react一些概念

    <!--public/index.html简化如下-->
    <!
    DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <title>React App</title> <style> body { margin: 0; padding: 0; } </style> </head> <body> <div id="root"></div> </body> </html>

      react简单示例只保留简化后的public/index.html和src/index.js

      1.React.Component

      React.Component是自定义组件的父类,必须重写render方法来完成组件的声明和返回。所谓组件,就是用js类定义的一组html标签、样式、数据、事件等的整合,该类可以用<类名 />的方式进行标签化(实例化),实例化时自动调用render方法,并最终交由React.render完成渲染。

      一张网页就可以分割成多个组件,每个组件自己实现标签、样式、数据交互和用户交互。也就是说,网页是由多个组件堆砌而成的,每个组件都必须继承React.Component来实现并返回自己的定制化。显然地,组件既包含一个div标签组,本身也是一个类,它具有双重角色。

      一个继承了React.Component的组件,通过render返回一个组件对象。经验上谈,一个子类的某个固定方法极有可能是其父类方法(或接口)的重写(实现),而往往这个方法会在程序运行时被自动调用。因此,render方法是重写了React.Component,在程序启动时被自动执行,挂载到网页的某个节点上。

    import React, {Component, Fragment} from "react";
    
    class Boom extends Component{
        render() {
            return (
                <Fragment>
                    <div>
                        <input /><button>提交</button>
                    </div>
                    <ul>
                        <li>what the hell?</li>
                        <li>你瞅啥子</li>
                    </ul>
                </Fragment>
            )
        }
    }
    
    export default Boom;

      2.ReactDOM.render

      index.js中的ReactDOM.render函数用于将标签或者组件渲染到public下的页面中。第一个参数可以是任意的单个标签、div包裹的多个标签,以及自定义的组件Component。

      ReactDOM.render用于将组件挂载到某个标签上。比如html中某个id为root的div标签上。简单粗暴:一个包含了西瓜瓤、西瓜籽、西瓜皮的西瓜挂在了西瓜藤上。

      3.React JSX

      用于编译jsx语法。React.Component和ReactDOM.render中的标签都使用了jsx语法,所以必须使用React进行编译。JSX看起来像是急于XML的javascript的扩展。它编写简单并且执行更快,同时也是类型安全的,在编译过程中就能发展错误。

      经验之谈:如果一个标签的首字母时大写,那么它就遵循JSX语法,如果一个标签的首字母小写,那么它就是原始html标签(但这个标签有可能是按照jsx语法编译的)。

      JSX允许在一对{}中写js代码,例如:

    {
         /*
              遍历list生成li标签,并给每个li标签添加删除功能
         /
         this.state.list.map(
              (item, index) => {
                    return <li
                                key={index}
                                onClick={(index)=>{this.handleLiDelete(index)}}
                           > { item }</li>
              }
    ) }

      4.组件内部参数声明和使用

      组件内部可以声明参数,无论是textNode还是其它Node,都是以 { 参数 } 的形式被组件调用。组件react虚拟DOM的具体实现方式,它来完成对页面和业务逻辑的划分。

    // src/index.js
    import React from 'react';
    import ReactDOM from 'react-dom';

    class App extends React.Component{
    render (){
    const string = "hello, react!";
    const style1 = {
    color: "white"
    };
    const style2 = {
    textAlign:"center",
    fontStyle: "border",
    backgroundColor: "green"
    };
    return (
    <div style={style1}>
    {/*这是一段注释*/}
    <h2 style={style2}>{ string }</h2>
    </div>
    )
    }
    }

    ReactDOM.render(<div>
    <h2>hello, react!</h2>
    <App />
    </div>, document.getElementById('root'));

      组件间可以实现嵌套。

    import React from 'react';
    import ReactDOM from 'react-dom';

    class App extends React.Component{
    render (){
    return <h2>这是子组件</h2>
    }
    }
    class App2 extends React.Component{
    render (){
    const style = {
    backgroundColor: "blue"
    };
    return (
    <div style={style}>
    <h2>这是父组件</h2>
    <App />
    </div>
    )
    }
    }

    ReactDOM.render(<App2 />, document.getElementById('root'));

      5.静态数据传递--props

      组件间数据通过this.props属性来进行数据传递。父组件在标签化时通过属性的方式传递数据,子组件通过this.props来获取所有的数据。

    import React from 'react';
    import ReactDOM from 'react-dom';

    class App extends React.Component{
    render (){
    return <h2>App: { this.props.name }, { this.props.age }</h2>
    }
    }
    class App2 extends React.Component{
    render (){
    const name = "Sun", age=5000;

    return (
    <div>
    <h2>App2: { this.props.name }, { this.props.age }</h2>
    <App name={name} age={age} />
    </div>
    )
    }
    }
    ReactDOM.render(<App2 name="Li" age="20" />, document.getElementById('root'));

      注意:1.props只能传递静态数据,无法与用户交互;2.{}不是Object对象,如果想写<App2 obj={name: "Li", age: 20} />,就必须提前声明。3.style样式作为数据传递是无效且荒谬的。

    const obj = {name: "Li",age: 20};
    <App2 obj={obj}/>

      6.动态数据交互--state

      React是一个响应式框架,它将数据和dom分开,能够根据数据的变化自动更新dom。再次强调:React.Component具有双重属性:组件(dom)属性和js类属性(类:数据封装)。

      state用于负责处理动态数据。数据需要在构造函数中通过this.state事先声明,并在事件中通过this.setSate完成数据更新。

    import React from 'react';
    import ReactDOM from 'react-dom';

    class App extends React.Component{
    constructor(props){
    super(props);
    this.state = {
    nameList:["Sun", "Li", "Zhao", "Qian"]
    }
    }
    addPerson(){
    this.setState({
    nameList: [...this.state.nameList, "zhou"]
    })
    }
    render (){
    return (
    <div>
    <button onClick={()=>this.addPerson()}>加入周先生</button>
    <ul>
    {this.state.nameList.map((name, index) => <li key={index+1}>{name}</li>)}
    </ul>
    </div>

    )
    }
    }
    ReactDOM.render(<App />, document.getElementById('root'));

      7.事件绑定

      在react中,事件以属性的方式直接在标签中使用,其调用函数要用一层函数包裹。调用函数可以直接写在对象内部,并且要用bind进行监听和更新。

      在上面的示例中,我们通过这一行代码代替了bind的过程:

    <button onClick={()=>this.addPerson()}>加入周先生</button>

      鉴于js中没有局部作用域只有函数作用域,所以如果直接写onClick={this.addPerson}时,this指的就是window对象。用一层函数包裹时,this对象指的就是这个函数。

      其它的做法有两种:

      首先,在事件绑定时直接使用this.function:

    <button onClick={this.addPerson}>加入周先生</button>

      其次可以用箭头函数来声明addPerson函数,本质上和上面使用的方法一样:

    addPerson = ()=>{
    this.setState({
    nameList: [...this.state.nameList, "zhou"]
    })
    };

      或者可以不改addPersonn函数,而是在构造器中添加上这么一句话:

    this.addPerson = this.addPerson.bind(this)

      一个示例:

    import React, {Component, Fragment} from "react";
    
    class Boom extends Component{
        constructor(props){
            super(props);
            this.state = {
                inputValue: "",
                list: []
            }
        }
        handleInputChange(e){
            this.setState({
                inputValue: e.target.value
            });
        }
        handleBtnClick(){
            this.setState({
                list:[...this.state.list, this.state.inputValue],
                inputValue: ""     // 在提交时自动清空输入框里的内容
            })
        }
    
        handleLiDelete(index){
            const list = [...this.state.list]; // 只能通过setState修改数据,所以不要写成this.state.list.splice(index, 1);
            list.splice(index, 1);
            this.setState({
                list: list
            });
        }
        render() {
            return (
                <Fragment>
                    <div>
                        <input
                            value={ this.state.inputValue }
                            onChange={this.handleInputChange.bind(this)}
                        />
                        <button onClick={()=>this.handleBtnClick()}>提交一个句子</button>
                    </div>
                    <ul>
                        {
                            this.state.list.map(
                                (item, index) => {
                                    return <li
                                                key={index}
                                                onClick={(index)=>{this.handleLiDelete(index)}}
                                            > { item }</li>
                                }
                            )
                        }
                    </ul>
                </Fragment>
            )
        }
    }
    
    export default Boom;

      8.条件渲染

      render本身是一个实例方法,支持js中的各种代码逻辑。可以用if-else来控制返回结果。条件渲染在用户登录和重定向中使用的比较频繁。

    // src/index.js
    import React from 'react';
    import ReactDOM from 'react-dom';

    class App extends React.Component{
    constructor(props){
    super(props);
    this.state = {isLogIn: false}

    }
    login (){
    this.setState({isLogIn: true})
    };
    logout(){
    this.setState({isLogIn: false})
    }
    render (){
    let button=null;
    if (this.state.isLogIn){
    button = <button onClick={()=>this.logout()}>注销</button>
    }else {
    button = <button onClick={()=>this.login()}>登录</button>
    }
    return button
    }
    }
    ReactDOM.render(<App />, document.getElementById('root'));

      也可以用三元表达式简写:

    render (){
    return (
    <div>
    {this.state.isLogIn ? <button onClick={()=>this.logout()}>注销</button> : <button onClick={()=>this.login()}>登录</button>}
    </div>
    )
    }

      注意:由于{}传递的数据可以是任意值,所以需要用div包裹。

  • 相关阅读:
    js 图片压缩
    C#.NET中对称和非对称加密、解密方法汇总--亲测可用
    最精美详尽的 HTTPS 原理图
    swagger ui
    python爬取百度谷歌搜索结果
    Gitlab 11.0.3 迁移简明笔记
    ELK stack 7.6.x + kafka构建日志平台
    Nginx 内存占用高排查
    运维机器人 hubot 集成 jenkins
    运维机器人hubot,解放运维的神器
  • 原文地址:https://www.cnblogs.com/kuaizifeng/p/9388292.html
Copyright © 2011-2022 走看看