React 笔记 1

React是FaceBook(脸书)公司研发的一款JS框架(MVC)

1.React的脚手架

React是一款框架:具备自己开发的独立思想(MVC:Model View Controller)

-> 划分组件开发

-> 基于路由的SPA单页面开发

-> 基于ES6来编写代码(最后部署上线的时候,我们需要把ES6编译成ES5 =>基于Babel来完成编译)

-> 可能用到Less/Sass等,我们也需要使用对应的插件把他们进行预编译

-> 最后为了优化性能(减少HTTP请求次数),我们需要把JS或者CSS进行合并压缩

-> ...

-> webpack来完成以上页面组件合并、JS/CSS编译加合并等工作

前端工程化开发:

=>基于框架的组件化/模块化开发

=>基于WEBPACK的自动部署

        但是配置WEBPACK是一个相对复杂的工作,我们需要自己安装很多的包,还需要自己写相对复杂的配置文件...如果我们有一个插件,基于它可以快速构建一套完整的自动化工程项目结构,那么有助于提高开发的效率 =>“脚手架” VUE:VUE-CLI REACT:CREATE-REACT-APP

【create-react-app 的使用】

>$ npm install create-react-app -g

把模块安装在全局环境下(目的:可以使用命令),MAC电脑安装的时候,前面需要加SUDO,否则没有权限

>$ create-react-app [项目名称]
//基于脚手架命令,创建出一个基于React的自动化/工程化项目目录,和npm发包时候的命名规范一样,项
//目名称中不能出现:大写字母、中文汉字、特殊符号(-或者_是可以的)等

【脚手架生成目录中的一些内容】

node_modules 当前项目中依赖的包都安装在这里

        .bin 本地项目中可执行命令,在package.json的scripts中配置对应的脚本即可(其中有一个就是:react-scripts命令)

        public 存放的是当前项目的HTML页面(单页面应用放一个index.html即可,多页面根据自己需求放置需要的页面)

   <!--
         在REACT框架中,所有的逻辑都是在JS中完成的(包括页面结构的创建),如果想给当前的页面导入一些CSS样式或者IMG图片等内容,我们有两种方式:
           1.在JS中基于ES6 Module模块规范,使用import导入,这样webpack在编译合并JS的时候,会把导入的资源文件等插入到页面的结构中(绝对不能在JS管控的结构中通过相对目录./或者../,导入资源,因为在webpack编译的时候,地址就不在是之前的相对地址了)
           2.如果不想在JS中导入(JS中导入的资源最后都会基于WEBPACK编译),我们也可以把资源手动的在HTML中导入,但是HTML最后也要基于WEBPACK编译,导入的地址也不建议写相对地址,而是使用 %PUBLIC_URL% 写成绝对地址
        <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
        <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    -->

src 项目结构中最主要的目录,因为后期所有的JS、路由、组件等都是放到这里面(包括需要编写的CSS或者图片等)
  index.js 是当前项目的入口文件 

.gitignore  Git提交时候的忽略提交文件配置项 

  # webStorm       .idea

package.json  当前项目的配置清单
   "dependencies": {
       "react": "^16.4.1",
       "react-dom": "^16.4.1",
       "react-scripts": "1.1.4"
   }
   基于脚手架生成工程目录,自动帮我们安装了三个模块:react/react-dom/react-scripts
   react-scripts集成了webpack需要的内容
      ->Babel一套
      ->CSS处理的一套
      ->eslint一套
      ->webpack一套
      ->其它的
   没有less/sass的处理内容(项目中使用less,我们需要自己额外的安装)
​
   ----
​
   "scripts": {
       "start": "react-scripts start",
       "build": "react-scripts build",
       "test": "react-scripts test --env=jsdom",
       "eject": "react-scripts eject"
   }
   可执行的脚本“$ npm run start / $ yarn start”
      start:开发环境下,基于webpack编译处理,最后可以预览当前开发的项目成果(在webpack中安装了webpack-dev-server插件,基于这个插件会自动创建一个WEB服务[端口号默认是3000],webpack会帮我们自动打开浏览器,并且展示我们的页面,并且能够监听我们代码的改变,如果代码改变了,webpack会自动重新编译,并且刷新浏览器来完成重新渲染)
​
      build:项目需要部署到服务器上,我们先执行 yarn build,把项目整体编译打包(完成后会在项目中生成一个build文件夹,这个文件夹中包含了所有编译后的内容,我们把它上传到服务器即可);而且在服务上进行部署的时候,不需要安装任何模块了(因为webpack已经把需要的内容都打包到一个JS中了)

2.React脚手架的深入剖析

create-react-app脚手架为了让结构目录清晰,把安装的webpack及配置文件都集成在了react-scripts模块中,放到了node_modules中

但是真实项目中,我们需要在脚手架默认安装的基础上,额外安装一些我们需要的模块,例如:react-router-dom/axios... 再比如:less/less-loader...

情况一:如果我们安装其它的组件,但是安装成功后不需要修改webpack的配置项,此时我们直接的安装,并且调取使用即可(yarn add qs)

在src下的index.js中导入  import qs from 'qs';

console.log(qs.parse('name=react&age=18'));

import from './static/less/index.less';

情况二:我们安装的插件是基于webpack处理的,也就是需要把安装的模块配置到webpack中(重新修改webpack配置项了)

        =>首先需要把隐藏到node_modules中的配置项暴露到项目中

        > $ yarn eject

首先会提示确认是否执行eject操作,这个操作是不可逆转的,一但暴露出来配置项,就无法在隐藏回去了
​
如果当前的项目基于GIT管理,在执行eject的时候,如果还有没有提交到历史的区的内容,需要先提交到历史区,然后在eject才可以,否则报错:This git repository has untracked files or uncommitted changes...
​
=>再去修改对应的配置项即可
  一但暴露后,项目目录中多了两个文件夹:
    config  存放的是webpack的配置文件
       webpack.config.dev.js  开发环境下的配置项(yarn start)
       webpack.config.prod.js  生产环境下的配置项(yarn build)
​
    scripts 存放的是可执行脚本的JS文件
       start.js   yarn start执行的就是这个JS
       build.js   yarn build执行的就是这个JS
​
  package.json中的内容也改了
​
  【举个栗子:需要配置LESS】
      $ yarn add less less-loader
​
      less是开发和成产环境下都需要配置的
修改webpack.config.dev.js 和 webpack.config-prod.js 中        
      ```
        {
            test: /\.(css|less)$/,
            use: [
                require.resolve('style-loader'),
                ...
                {
                    loader: require.resolve('less-loader')
                }
            ],
        },
      ```dev 231{test: /\.less$/,loader: require.resolve('style-loader')}/prod 108

我们预览项目的时候,也是先基于webpack编译,把编译后的内容放到浏览器中运行,所以如果项目中使用了less,我们需要修改webpack配置项,在配置项中加入less的编译工作,这样后期预览项目,首先基于webpack把less编译为css,然后在呈现在页面中.

$ set HTTPS=true&&npm start 开启HTTPS协议模式(设置环境变量HTTPS的值)

$ set PORT=63341 (修改端口号)

$ set HTTPS=false&&set PORT=3000&&yarn start(修改为默认端口号)

====================================

二. react & react-dom

【渐进式框架】

        一种最流行的框架设计思想,一般框架中都包含很多内容,这样导致框架的体积过于臃肿,拖慢加载的速度。真实项目中,我们使用一个框架,不一定用到所有的功能,此时我们应该把框架的功能进行拆分,用户想用什么,让其自己自由组合即可。

 全家桶:渐进式框架N多部分的组合
​
 VUE全家桶:vue-cli/vue/vue-router/vuex/axios(fetch)/vue element(vant)
 REACT全家桶:create-react-app/react/react-dom/react-router/redux/react-redux/axios/ant/dva/saga/mobx...
  1. react:REACT框架的核心部分,提供了Component类可以供我们进行组件开发,提供了钩子函数(生命周期函数:所有的生命周期函数都是基于回调函数完成的)

  2. react-dom:把JSX语法(REACT独有的语法)渲染为真实DOM(能够放到页面中展示的结构都叫做真实的DOM)的组件

 * ReactDOM.render([JSX],[CONTAINER],[CALLBACK]):把JSX元素渲染到页面中

 *   JSX:REACT虚拟元素

 *   CONTAINER:容器,我们想把元素放到页面中的哪个容器中

 *   CALLBACK:当把内容放到页面中呈现触发的回调函数

 *

 * JSX:REACT独有的语法  JAVASCRIPT+XML(HTML)

 *   和我们之前自己拼接的HTML字符串类似,都是把HTML结构代码和JS代码或者数据混合在一起了,但是它不是字符串

 *

 *   1.不建议我们把JSX直接渲染到BODY中,而是放在自己创建一个容器中,一般我们都放在一个ID为ROOT的DIV中即可

 *

 *   2.在JSX中出现的{}是存放JS的,但是要求JS代码指执行完成有返回结果(JS表达式)

 *     ->不能直接放一个对象数据类型的值(对象(除了给style赋值)、数组(数组中如有没有对象,都是基本值或者是JSX元素,这样是可以的)、函数都不行)

 *     ->可以是基本类型的值(布尔类型什么都不显示、null、undefined也是JSX元素,代表的是空)

 *     ->循环判断的语句都不支持,但是支持三元运算符

 *

 *   3.循环数组创建JSX元素(一般都基于数组的MAP方法完成迭代),需要给创建的元素设置唯一的KEY值(当前本次循环内唯一即可)

 *

 *   4.只能出现一个根元素

 *

 *   5.给元素设置样式类用的是className而不是class

 *

 *   6.style中不能直接的写样式字符串,需要基于一个样式对象来遍历赋值

import React from 'react';
import reactDom from 'react-dom';
import './index.css';

let root = document.querySelector('#root')
let data = '你好世界'
let arr=[{name:'zhangsan',age:18},{name:'lisi',age:20}]
reactDom.render( <div id = "obox"> hello world { data } </div>,root,()=>{
    let obox = document.querySelector('#obox')
    console.log(obox);
});
reactDom.render( <div className=”box“ style={{color:”red“}}>
    <ul>
        {arr.map((item,index)=>{
            let {name,age} = item;
            return <li key={index}>
                    <span>{name}</span>
                    <span>{age}</span>
              </li>;
        })}
    </ul>
</div>,root);

三、把JSX(虚拟DOM)变为真实的DOM 

 * JSX渲染机制

 *   1.基于BABEL中的语法解析模块(BABEL-PRESET-REACT)把JSX语法编译为 React.createElement(...) 结构

 *     React.createElement(

           'h1',

           {id: 'titleBox',className: 'title',style: styleObj},

           '\u73E0\u5CF0\u57F9\u8BAD' ->珠峰培训

       );

 *

 *   2.执行React.createElement(type, props, children),创建一个对象(虚拟DOM)

 *     type:'h1'

 *     props:{

 *        id:'titleBox',

 *        className:'title',

 *        style:...,

 *        children:'珠峰培训'   =>存放的是元素中的内容

 *     }

 *     ref:null

 *     key:null

 *     ...

 *     __proto__:Object.prototype

 *

 *  3.ReactDOM.render(JSX语法最后生成的对象,容器),基于RENDER方法把生成的对象动态创建为DOM圆度,插入到指定的容器中

let styleObj = {color:'red'}
render(<div id='box' className='box'>
    <h1 id=‘titleBox className='title' style={styleObj}>珠峰培训</h1>
    <ul className='newsList'>
        <li>数据1</li>
        <li>数据2</li>
        <li>数据3</li>
    </ul>
    我就是测试着玩
</div>, root);

自己实现一个方法实现createElement

 * 1.创建一个对象(默认有四个属性:TYPE/PROPS/REF/KEY),最后要把这个对象返回

 *

 * 2.根据传递的值修改这个对象

 *   TYPE =>传递的TYPE

 *   PROPS 需要做一些处理:大部分传递PROPS中的属性都赋值给对象的PROPS,有一些比较特殊

 *     ->如果是REF或者KEY,我们需要把传递的PROPS中的这两个属性值,给创建对象的两个属性,而传递的PROPS中把这两个值删除掉

 *     ->把传递的CHILDREN作为新创建对象的PROPS中的一个属性

function createElement(type, props, children) {
    props = props || {};
    //=>创建一个对象,设置一些默认属性值
    let obj = {
        type: null,
        props: {children: ''},
        ref: null,
        key: null
    };
    //=>用传递的TYPE和PROPS覆盖原有的默认值
    // obj = {...obj, type, props};//=>{type:type,props:props}
    obj = {...obj, type, props: {...props, children}};
    //=>把REF和KEY提取出来(并且删除PROPS中的属性)
    'key' in obj.props ? (obj.key = obj.props.key, obj.props.key = undefined) : null;
    'ref' in obj.props ? (obj.ref = obj.props.ref, obj.props.ref = undefined) : null;
    return obj;
}

let objJSX = createElement(
    'h1',
    {id: 'titleBox', className: 'title', style: {color: 'green'}, ref: 'AA', key: '12'},
    '\u73E0\u5CF0\u57F9\u8BAD'
);

  * RENDER:把创建的对象生成对应的DOM元素,最后插入到页面中

function render(obj, container, callBack) {
    let {type, props} = obj || {},
        newElement = document.createElement(type);
    for (let attr in props) {
        if (!props.hasOwnProperty(attr)) break;//=>不是私有的直接结束遍历
        if (!props[attr]) continue;//=>如果当前属性没有值,直接不处理即可

        let value = props[attr];
        //=>CLASS-NAME
        if (attr === 'className') {
            newElement.setAttribute('class', value);
            continue;
        }

        //=>STYLE
        if (attr === 'style') {
            if (value === '') continue;
            for (let styKey in value) {
                if (value.hasOwnProperty(styKey)) {
                    newElement['style'][styKey] = value[styKey];
                }
            }
            continue;
        }

        //=>CHILDREN
        if (attr === 'children') {
            if (typeof value === 'string') {
                let text = document.createTextNode(value);
                newElement.appendChild(text);
            }
            continue;
        }

        //=>基于SET-ATTRIBUTE可以让设置的属性表现在HTML的结构上
        newElement.setAttribute(attr, value);
    }
    container.appendChild(newElement);
    callBack && callBack();
}

render(objJSX, root, () => {
    console.log('ok');
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值