(2)前端React入门学习--基础入门部分02(仔细了解)

1、React的基本概念

1、单页模型(spa):新的网页开发模型,就是说当要浏览不同的网页时,客户端不用去频繁的想服务器发起请求,只需要将新页面的数据拉取下来,根据客户端的具体情况在本地重新绘制新的界面,将新的数据展现在本地构建的新的页面。整个过程减少了客户端和服务端的交互延迟,能够及时的响应。

2、单页模型的困境:

(1)如何保持数据和UI同步的更新,就是新的数据和新的本地界面能同时的更新。

(2)如何提高DOM操作的效率。

(3)html开发UI界面异常的复杂

3、React的及时登场(React的好处)

(1)自动化的UI管理(使得界面和数据能够保持同步,数据的变换转化为事件,开发者只需要根据事件去改变界面的状态,简单的说整个流程就是:数据的变化->事件的发生->界面的更新)

(2)高效的DOM操作效率

在内存中存在Virtual DOM的结构,对DOM的操作转化为对虚拟DOM的操作,提高了效率。

(3)UI的组件化设计,可重用的组件和简单的组件能够组合成为复杂的组件,使用JSX减少对CSS的样式依赖。

4、总结:React实际上是MVC架构中的V,就是view部分,由于UI的组件化设计、自动化的UI管理、高效的DOM操作效率这单个特性,使得React大幅度减少了数据和页面交互的难度(这句话必须要记住)

5、react fiber指的是React 16这个大版本。

2、开发环境的搭建

1、使用脚手架工具,在 脚手架中写的代码并不能直接运行,需要靠工具来进行编译,编译后的代码才能被浏览器进行识别。关于脚手架工具有GRUNT,gulp,webpack,这些脚手架工具不必自己实现,会用就可以,但是关于脚手架工具的编写是可以单独作为一个系列的课程来学的。

2、关于脚手架的工具建议使用官方的Create-react-app

3、在有node的环境前提下(在命令行中可以使用node -v 和npm -v来查看自己node和npm的版本),使用命令npm install -g create-react-app,来下载官方脚手架工具。

4、在window操作系统下,将shift和鼠标右键同时按下,点击在此处打开命令窗口:

(1)使用命令creat-react-app todolist来在桌面上创建一个todolist的文件夹。

(2)然后在命令行中cd todolist 。

(3)输入yarn start运行项目(有的是npm start)。

(4)会自动打开浏览器显示这样一个网页,网址是localhost:3000,网页内容如下:

到这里为止我们就用官方的脚手架创建了一个react的项目。

3、项目文件的结构

(1)图中的public中的favicon.ico是我们网页最上面每一个导航条里面最左边的小图标。

(2)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">
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
  </body>
</html>

(3)那么src是最重要的一个目录,这里放着我们所有的源代码,所有源代码的入口就是这个index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

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

前面都是一些模块的引入,特别是这个App文件,没有后缀,但是项目会自动去先找App.js这个文件,也就是会自动补全后缀。那么下面正文就不用多说,将<App>这个视图插入到root这个DOM结点中,root这个容器在哪里,就在public文件夹中index.html文件中,那么空的容器,它的id叫做root。

还有registerServiceWorker是什么东西,这里就有个很重要的概念,pwa,progrcessive web application,就是使用写网页的方式去写一些手机app ,那么这个有啥功能,除了帮助写手机app,假如我们这个网页上线到一个https的服务器上,我们的网页就有这样的特性,第一次访问需要联网,第二次断网的时候,也能访问到一样的页面,因为 registerServiceWorker帮助存储在了浏览器当中。

(4)那么有了pwa的概念后我们回头去看看manifest.json里面的内容

{
  "short_name": "React App",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    }
  ],
  "start_url": "./index.html",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

我们有了缓存,我们在桌面上和手机上就可以创建快捷方式,直接进入这个网址,快捷方式的图标就是icons来定义的,快捷方式的跳转网址就是start_url定义的,还有主题颜色和背景颜色等等。

(5)下面来看看这个App是什么内容:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

export default App;

其中这个logo就是我们那个页面中旋转的react 的logo,可以看到return内容中的很多标签都有className,它们用来记录这个标签,能在App.css文件中定义样式。

4、组件基础

1、组件化的思想使得复杂的页面简单化。

2、一个类继承component,它就变成了一个组件。其中render函数中return什么,组件就显示什么。

3、ReactDOM.render(<App />, document.getElementById('root')) 这个方法帮我们将组件挂载到某个DOM节点上,这句话就是将App这个组件挂载到id=root的这个结点之下。特别注意的是:我们这句话中使用了<App/ >这样的JSX的语法,那么我们这个文件就必须要将React引入进来,即import React from 'react' 这句话不能少,否则就不能编译通过。

4、还有一种情况,如下图

export default class App extends Component{
    render(){
        return (
            <div/>hello</div>
        )
    }
}

表面上看起来div是html的标签,实际上在react中,这些标签都是JSX的语法,也就是说都是组件,react组件分为自定义组件和原生组件,上面我们说的App就是个自定义的组件,而div就是原生的组件。使用JSX语法就一定要引入React。即import React from 'react' 这句话不能少。

5、JSX是什么

1、在js中使用像html的标签的写法就是JSX,但是记住,如果是自己定义的组件,首字母要大写,例如App组件,不能写成app组件,JSX语法是不支持的。

2、有一种简单的判断方法,一般<>中组件的首字母大写,就是自定义组件,小写就是原生的组件。

6、Fragment

1、在JSX语言当中我们render函数只允许去放回一个试图组件,也就是说当我们把代码写成下面这样是不行的:

render(){
        return (
                <div style={{marginTop:10}}>
                    <input/><button>提交</button>
                </div>
                <ul>
                    <li>学英语</li>
                    <li>learn react</li>
                </ul>
        )
    }

因为return中返回了两个视图组件,所以我们要在俩个视图组件外面去包裹一个div,但是有些时候我们就像把两个组件分开,不想让它们在一个div中,那么我们可以使用占位符Fragment,这样在浏览器上就不会报错:(注意引入Fragment)

import React,{Component,Fragment} from 'react';
export default class Todolist extends Component{
    render(){
        return (
            <Fragment>
                <div style={{marginTop:10}}>
                    <input/><button>提交</button>
                </div>
                <ul>
                    <li>学英语</li>
                    <li>learn react</li>
                </ul>
            </Fragment>
        )
    }
}

7、React中的响应式思想和事件绑定(重要)

1、响应式的思想是这样的,我们不用去操作DOM,去操作数据,因为React会自动感知数据的变化,自动的帮你生成DOM,所以我们不必去关注DOM,去关注数据。

2、我们在写一个类的构造函数有一种固定的写法:

constructor(props){
        super(props);
    }

因为我们自定义的类去继承component,那么在写自己的构造函数的时候要调用一次父类的构造函数,super就是这个功能。

3、在JSX语法中,要使用JS的变量和表达式,要在外部用大括号包起来。例如下面

<input value={this.state.value}/><button>提交</button>

this.state.value是JS的变量,写在JSX中使用{}将其包裹起来。

4、React在英文当中的意思是响应,假如页面的组件的属性和数据进行绑定,那么数据的变化会自动导致页面的属性变化,从而导致页面的变化。

5、this+bind、箭头函数两者形成的三种写法

(1)onChange={this.handleChangeInput}      handleChangeInput=(event)=>{}

 handleChangeInput=(event)=>{      
        this.setState({
            inputValue:event.target.value
        })
    }
    render(){
        return (
            <Fragment>
                <div style={{marginTop:10}}>
                    <input 
                        value={this.state.inputValue}
                        onChange={this.handleChangeInput}
                    />
                    <button>提交</button>
                </div>
            </Fragment>
        )
    }

(2)onChange={this.handleChangeInput.bind(this)}     handleChangeInput(event){}

handleChangeInput(event){
        this.setState({
            inputValue:event.target.value
        })
    }
    render(){
        return (
            <Fragment>
                <div style={{marginTop:10}}>
                    <input 
                        value={this.state.inputValue}
                        onChange={this.handleChangeInput.bind(this)}
                    />
                    <button>提交</button>
                </div>
            </Fragment>
        )
    }

(3)onChange={(event)=>this.handleChangeInput(event)}     handleChangeInput(event){}

 handleChangeInput(event){
        this.setState({
            inputValue:event.target.value
        })
    }
    render(){
        return (
            <Fragment>
                <div style={{marginTop:10}}>
                    <input 
                        value={this.state.inputValue}
                        onChange={(event)=>this.handleChangeInput(event)}
                    />
                    <button>提交</button>
                </div>
            </Fragment>
        )
    }

6、数据驱动的过程:通过下面这个输入框中输入内容的程序来深度讲解

import React,{Component,Fragment} from 'react';
export default class Todolist extends Component{

    constructor(props){
        super(props);
        this.state={
            inputValue:'',
            list:[],
        }
    }
    handleChangeInput(event){
        this.setState({
            inputValue:event.target.value
        })
    }
    render(){
        return (
            <Fragment>
                <div style={{marginTop:10}}>
                    <input 
                        value={this.state.inputValue}
                        onChange={(event)=>this.handleChangeInput(event)}
                    />
                    <button>提交</button>
                </div>
            </Fragment>
        )
    }
}

(1)首先 inputValue:''表示:inputValue的初始状态为空

(2)value={this.state.inputValue} 表示:输入框中的内容是inputValue

(3)你在输入框中输入字母的时候实际上发生了一个事件event

(4)在这个事件event中记录了你的输入event.target.value

(5)我们将输入框中的内容inputValue改变成event事件里已记录的你刚输入的字母

(6)数据inputValue变化,通过value={this.state.inputValue}来告知了输入框,你显示的内容该变了

7、展开运算符

this.setState({
    list:[...this.state.list,this.state.inputValue]
})

这个是ES6中的写法,就是重新构建个数组,这个数组是由之前的数组里面所有的旧内容和新的内容this.state.inputValue共同组成,这里就用...this.state.list将之前数组中所有的旧内容全部展开放在这里,和this.state.inputValue共同成为这个新数组中的所有成员。

8、immutable

(1)当我们要去改变state中的内容,要使用this.setState({})这个方法,不能去直接操作state中的内容。

(2)像数组中的操作,我们要拷贝一份state中的副本,去修改副本,然后将副本通过this.setState的方法传给数组。下面这种写法就是错误的:

this.state.list.splice(index,1)
this.setState({
    list:this.state.list
})

正确的写法这样:

let list=[...this.state.list];    //拷取state数组的副本
list.splice(index,1);             //修改副本
this.setState({
    list:list,                    //副本传回值
})

8、其他JSX语法补充

1、借助脚手架的能力,在js文件当中可以去引入css文件。可以直接去引入这个css文件。

import './style.css';

使用的时候采用组件属性的calssName=‘input’,input在css文件中是个选择器,也可以叫做类:

.input{
    border:1px solid red
}

2、

(1)在JSX中显示一些内容,但这些内容我们不希望转义一些内容,比如我们在input输入框中输入<h1>hello world</h1>,它会自动转义,显示原原本本的<h1>hello world</h1>字符串,那么我们不希望转义的时候使用dangerouslySetInnerHTML这个属性。

(2)所以dangerouslySetInnerHTML的功能就是使我们某些标签里的内容不被转义。

比如我们原来的代码是

<li 
    key={index} 
    onClick={(index)=>this.handleItemDelete(index)}
>{item}</li>

使用了dangerouslySetInnerHTML这个属性之后

<li 
    key={index} 
    onClick={(index)=>this.handleItemDelete(index)}
    dangerouslySetInnerHTML={{__html:item}}
></li>

特别注意的是{{}}的含义,外层的{}表示这里面是个JS的表达式,里面的{}表示这是个对象。其中item就是我们设置不转义的内容。

3、label的使用

(1)在html中我们对label的定义是:

<label> 标签为 input 元素定义标注(标记)。

label 元素不会向用户呈现任何特殊效果。不过,它为鼠标用户改进了可用性。如果您在 label 元素内点击文本,就会触发此控件。就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。

<label> 标签的 for 属性应当与相关元素的 id 属性相同。

(2)在react中,我们就不能用for来作为这个属性的名字,因为for是循环的代表,所以我们使用htmlFor来代替这个属性

<label htmlFor="insertAre">点击这里自动将焦点转到与标签相关的表单控件上</label>
input 
    id="insertAre"
/>

9、组件的传值

1、父组件向子组件传递值,通过属性的方法。子组件通过this.props.xxx来接受这个数据。

 return(
     <Todoitem 
        key={index} 
        content={item} 
        index={index}
        handleItemDelete={(index)=>this.handleItemDelete(index)}
    />
)

2、子组件向父组件传值,通过调用父组件的方法来修改父组件的内容。

import React,{Component} from 'react';

export default class Todoitem extends Component{
    constructor(props){
        super(props)
        this.handleClick=this.handleClick.bind(this)
    }
    render(){
        return<div onClick={this.handleClick}>{this.props.content}</div>
    }

    handleClick(){
        this.props.handleItemDelete(this.props.index)
    }
}

3、当父组件向子组件中传递很多值,在子组件中取值都要用到this.props.xxx,这样很长很麻烦,使用解构的写法,在使用属性值直接可以用xxx来代替this.props.xxx。简化代码的书写。

const {key,content,index,handleItemDelete}=this.props;

10、代码的优化

1、在新版的react中我们的setState已经不推荐使用老的写法,如下

handleChangeInput(event){
   this.setState({
       inputValue:event.target.value
   })
}

我们里面的对象可以换成函数

handleChangeInput(event){
     let value=event.target.value;
     this.setState(()=>{
        return {
            inputValue:value
        }
    })
}

在新版的语法中我们都可以使用小括号去代替return的对象,这个是ES6对return的简写

handleChangeInput(event){
     let value=event.target.value;     //变更数据event.target.value存在外层
     this.setState(()=>({
            inputValue:value           //内部使用变量value 
     }))
}

4、当我们使用的上面的setState中用箭头函数返回对象这种方式,就要注意它是一种异步的写法, 最好将变更的数据存在外层,在内层使用变量就行了。

5、展开运算符的进阶写法,使用prevState去代替this.state

handleBtnClick(){
    this.setState((prevState)=>({
        list:[...prevState.list,prevState.inputValue],
        inputValue:'',
    }))
}

6、当我们存在return{list:list}这种写法的时候我们后面的list可以省略,而且对变量list的操作拉进setState中

//新式写法
handleItemDelete(index){
       this.setState((prevState)=>{
            let list=[...prevState.list];
            list.splice(index,1);
            return{list}
       })
}

//旧时写法
handleItemDelete(index){
       let list=[...this.state.list];
       list.splice(index,1);
       this.setState({
           list:list,
       })
}

11、由react衍生出的思考

1、声明式的开发

     react的开发和jquery直接操作DOM的方式不同,不属于命令式的编程,以数据为主

2、可以和其它框架并存,因为下面的这个句话

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

整个Todolist的内容只挂载在rootDOM结点中,只影响root这个结点中的DOM结构。而html还有其它的div,其它div可以用其它框架去操作DOM,只要不影响root的DOM结构。

3、单项数据流

父组件可以去给子组件传值,但是这个值到了子组件中只有读的属性,没有写的属性,就是说子组件只能读取不能修改。原因是父组件中如果含有很多的子组件,每个子组件都能修改这个值,那其他组件的内容都会发生变化。而且出了问题不好定位。

4、React只是视图层的框架

由于父子传值的局限性,在不同的两个组件之间必须找到某种复杂的父子关系才能通信。大型项目忍不了!任何两个组件的通信都会有其他组件作为桥梁参与进来。所以React是负责页面和数据渲染的问题,React经常搭配其他数据工具来共同工作。比如FLUX,REDUX,MOBUX。

5、函数式编程

维护方便,前端自动化测试容易进行,给函数一个值看输出是否正确。

猜你喜欢

转载自blog.csdn.net/weixin_37968345/article/details/81066076