目录
Diffing算法
当页面上显示的内容更新时/初始化时,React会将需要更新/初始化的内容形成虚拟DOM,并和之前的虚拟DOM(如果有)进行比较,把需要更新的内容推到页面上,而不是整个DOM全部都更新。
key
key是虚拟DOM的一个标识,在对比更新时,key可以用于判断新旧虚拟DOM中前后节点是否是同一个。如果在旧虚拟DOM中找到了与新虚拟DOM中一样的key,则可以确定这两个节点是同一个,如果虚拟DOM中的内容没变,则直接复用,如果虚拟DOM中的内容改变了,则生成新的DOM并进行替换。如果旧虚拟DOM中没有和新虚拟DOM一样的key,会将这个DOM生成并渲染到页面。
如果将index索引值作为Key,在组数数据更新时,可能会产生效率问题。如果数据添加到组数最末尾,不会破坏前面的数据顺序,那么并不会影响效率,但是,如果数据插入了数组最前方或者数据中间某个位置,这会导致数组中元素的index和之前并不一致,diffing算法在进行比较时,会拿着两个其实并不一致的DOM对比,并认为数据发生了改变,会生成新的真实DOM并进行渲染,会重新渲染数据,而不是复用,产生效率问题。而且,如果标签内部含有输入类DOM(input输入框、radio单选器、checkbox、select等),当使用Index作为索引值时,动态插入数据时,如果数据并不是插入最末尾,输入框中的数据也会由于前后Index相同的DOM元素其实并不是同一个,导致Input数据发生错乱。
如果不存在对数据的逆序加入、删除等操作,使用index作为key并不会产生问题的,但是,一旦数据的顺序发生改变,使用index作为Key就会产生问题。
脚手架
create-react-app
create-react-app是React提供的一个脚手架,脚手架可以用于快速创建基于某个库的模板项目。包含了基础的需要的配置,并且可以下载好所需的相关依赖。使用脚手架,可以实现模块化、组件化、工程化。
安装
1.全局安装 npm install -g create-react-app
(如果提示网络错误,可以先设置npm config set registry http://registry.npmjs.org/
)
2.创建项目 create-react-app 项目名
3.进入项目名文件夹,启动项目 npm start
项目结构
public 静态资源文件,存放页面、公共图片、样式等
------index.html 应用主页面,组件都渲染到这个页面上,整个项目下只有一个html文件
------mainfest.json 应用加壳配置
------robots.txt 爬虫规则,当前网站被爬取时,规定哪些数据可以被爬取,哪些不行
src
------App.css APP组件样式
------App.js 生成App组件,组件首字母大写
------App.test.js APP组件测试文件
------index.css 通用样式,也可以放入public下,并在html中引入
------index.js 入口文件
------reportWebVitals.js 记录页面性能,内部使用web-vitals库,使用时需要自己编写配置,并不是完全配好的
------setupTests.js 用于组件测试,也是需要自己配置,使用了库jest-dom
public-index.html
src-index.js
hello world Demo
在react中,.js和.jsx文件import时可以省略扩展名
import './App.css';
import React from 'react'
class App extends React.Component{
render(){
return (
<div>
<h2>hello world</h2>
</div>
)
}
}
export default App;
在实际编写项目时,一般在src下创建components文件,把组件放入components文件中,每个组件一般也都是一个文件夹,里面放置组件的js和组件的其他资源文件等,最后在App组件中引入使用。
src/components/Hello/hello.css
h2{
background-color: aquamarine;
}
src/components/Hello/index.jsx
import {Component } from 'react'
import './hello.css'
export default class Hello extends Component{
render(){
return (
<div>
<h2>Hello</h2>
</div>
)
}
}
src/components/World/world.css
.world{
background-color:blueviolet;
}
src/components/World/index.jsx
import {Component } from 'react'
import './world.css'
export default class Hello extends Component{
render(){
return (
<div>
<h2 className='world'>World</h2>
</div>
)
}
}
src/App.js
import './App.css';
import React from 'react'
import Hello from './components/Hello'
import World from './components/World'
class App extends React.Component{
render(){
return (
<div>
<Hello/>
<World/>
</div>
)
}
}
export default App;
如果组件文件以js结尾,有时候,js结尾的文件并不是全是组件,一般为了区分组件和一般js文件,可以让组件的js文件名首字母大写,或者让组件文件以.jsx为扩展名。
样式模块化
对于两个组件,如果他们各有自己的css文件,且css文件中存在冲突的命名,则后引入的样式会覆盖先引入的文件,为了避免这种情况,首先,要给css的名字之前先加上module,然后,在引入样式时,给引入的样式命名,然后给组件中标签配置样式时,配置命名.样式,就可以避免冲突。
hello.module.css
.h2Demo{
background-color: aquamarine;
}
hello/index.jsx
import {Component } from 'react'
import hello from './hello.module.css'
export default class Hello extends Component{
render(){
return (
<div>
<h2 className={hello.h2Demo}>Hello</h2>
</div>
)
}
}
world.module.css
.h2Demo{
background-color:blueviolet;
}
world/index.jsx
import {Component } from 'react'
import world from './world.module.css'
export default class Hello extends Component{
render(){
return (
<div>
<h2 className={world.h2Demo}>World</h2>
</div>
)
}
}
对一个jsx文件,里面的内容框架是固定的,可以通过一些代码片段快速生成框架,不需要自己完全手敲。要实现这种效果,需要先安装插件:
然后再敲rcc,就能生成react类式组件的框架,
import React, { Component } from 'react'
export default class index extends Component {
render() {
return (
<div>index</div>
)
}
}
敲rfc能生成函数式组件的框架。
import React from 'react'
export default function index() {
return (
<div>index</div>
)
}
在插件的details部分,可以查看其他的代码片段:
组件化流程
1. 拆分组件:把界面拆分成一个个组件
2. 实现静态组件
使用组件实现静态页面的效果
3. 实现动态组件
3.1能够动态显示初始化数据
3.2能够交互
父组件给子组件传值
通过props传递。
父组件App.js
import './App.css';
import React from 'react'
import World from './components/World'
class App extends React.Component{
state = {
dataList:[
{id:'001',name:'a',flag:true},
{id:'002',name:'b',flag:true},
]
}
render(){
return (
<div>
<World dataList={this.state.dataList}/>
</div>
)
}
}
export default App;
子组件World/index.jsx
import {Component } from 'react'
import world from './world.module.css'
export default class Hello extends Component{
render(){
console.log(this.props.dataList)
return (
<div>
<h2>1</h2>
</div>
)
}
}
子组件给父组件传值
通过函数,父组件先通过props给子组件传递一个函数,子组件调用函数时,以参数的形式给父组件传递数据。
父组件App.js
import './App.css';
import React from 'react'
import Hello from './components/Hello'
import World from './components/World'
class App extends React.Component{
state = {
dataList:[
{id:'001',name:'a',flag:true},
{id:'002',name:'b',flag:true},
]
}
setList = (dataObj)=>{
let newList = [dataObj,...this.state.dataList]
console.log(newList)
this.setState({dataList:newList})
}
render(){
return (
<div>
<Hello setList={this.setList}/>
<World/>
</div>
)
}
}
export default App;
子组件Hello/index.jsx
import {Component } from 'react'
export default class Hello extends Component{
setData = ()=>{
this.props.setList(
{id:'003',name:'c',flag:false}
)
}
render(){
return (
<div>
<button onClick={this.setData}>click</button>
</div>
)
}
}