React基础知识
Posted sauronblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React基础知识相关的知识,希望对你有一定的参考价值。
1.React介绍
- react、vue、angular俗称前端框架三驾马车
- React起源于Facebook的内部项目,因为该公司对市场上所有的javascript MVC框架都不满意,就决定自己写一套,用来架设Instagram的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了
- React是一个用于构建用户界面的JavaScript库
- React主要用户构建UI,很多人认为React是MVC中的V(视图)
1.1.react特点
1.2.react和vue的区别
1.首先,这两个框架,都是以组件化的思想进行开发的!
2.从开发团队上进行比较:
- React的开发团队,是Facebook官方大牛团队,团队技术实力雄厚;
- Vue:第一版本,主要是作者尤雨溪进行维护。
3.从社区方面进行对比:
- React社区早,解决方案多
- Vue社区晚一点,解决方案相对少一点
4.从移动App开发方面:
- 使用React这门技术,可以分分钟转到ReactNative的开发中
- Vue这门技术,也提供了无缝的转移到移动端开发中,通过weex可以使用Vue的语法,进行移动端APP开发
1.3.react核心知识
1.3.1React核心概念
- 虚拟DOM(Virtual DOM)
- Diff算法(Diff Algorithm)
- 单向数据流渲染(Data Flow)
- 组件生命周期
- JSX
- 一切皆为组件
2.我的第一个React项目
推荐使用yarn来安装node包,时间更快
2.1.新建文件夹,初始化项目
mkdir react-demo cd react-demo npm init -y
2.2.安装依赖
yarn add react react-dom webpack webpack-cli webpack-dev-server babel babel-cli babel-core babel-loader@7 babel-preset-react babel-preset-env babel-preset-es2015
2.3.编写文件
2.3.1.新建webpack.config.js
目录下新建webpack配置文件webpack.config.js
module.exports = { entry: "./main.js", output: { path: "/", filename: "index.js" }, module: { rules: [ { test: /.js$/, exclude: /(node_modules)/, use: { loader: "babel-loader", options: { presets: [‘env‘, ‘react‘, ‘es2015‘] } } } ] } }
2.3.2.新建页面文件index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="root"></div> <script src="./index.js"></script> </body> </html>
2.3.3.新建入口文件main.js
目录下新建main.js
import React, { Component } from ‘react‘; import ReactDom from ‘react-dom‘; class App extends Component { render() { return <h1> Hello, world! </h1> } } ReactDom.render( <App />, document.getElementById(‘root‘) )
2.3.4.修改package.json
"scripts": { "start": "webpack-dev-server --inline --hot --open --port 8090 --mode development" },
2.3.5.运行
yarn start
3.脚手架-我的第一个React项目
create-react-app是react脚手架的名称
3.1.快速开始
npm5.2或者更高带来的一个新特性,可以不同全局安装脚手架,就可以直接使用脚手架
npx create-react-app my-app cd my-app yarn start
3.2.运行成功
3.3.项目结构
│ .gitignore git忽略清单
│ package.json 项目配置文件
│ README.md 说明文件
│
├─public 公共资源
│ favicon.ico 图标
│ index.html 首页html
│ manifest.json 缓存清单
│
└─src 源代码
App.css 组件的样式文件
App.js 组件文件
App.test.js 组件的测试文件
index.css 全局样式文件
index.js 入口文件
logo.svg logo图标
serviceWorker.js serviceWorker文件
4.JSX
jsx是React框架中的一种语法,它是JavaScript的语法拓展。既可以在js文件中写js逻辑代码,也可以在js文件中写HTML语言。
JSX是JavaScript XML的简写
import React from ‘react‘; import ReactDOM from ‘react-dom‘; // const App = () => <h1>我就是jsx</h1>; const App = function () { return ( <h1>我就是jsx</h1> ); } ReactDOM.render(<App />, document.getElementById(‘root‘));
4.1.JSX嵌套元素
组件中,必须返回一个根元素
如下列语法是错误的!
const App = function () { return ( <h1>我就是jsx</h1> <h1>我就是jsx</h1> ); }
假设想要在根目录下直接渲染2个标签,可以使用Fragment标签,类似vue中的template
引入Fragment组件
import React, { Fragment } from ‘react‘;
包裹标签
import React, { Fragment } from ‘react‘; import ReactDOM from ‘react-dom‘; const App = ()=> { return ( <Fragment> <h1>我就是jsx</h1> <h1>我就是jsx</h1> </Fragment> ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
4.2.JSX表达式
1.普通渲染
<h1>我就是jsx</h1>
2.数学表达式
<h1>{1 + 1}</h1>
3.字符串
<h1>{‘hello world‘}</h1>
4.bool类型-无法渲染
<h1>{isBoy}</h1>
5.使用变量
<h1>{msg}</h1>
6.三目运算符
<h1>{isBoy ? "男生" : "女生"}</h1>
7.调用方法
const format = (msg) => { return ‘---‘ + msg + ‘---‘; } <h1>{format(msg)}</h1>
8.使用对象
const person = { name: "沙和尚" }; <h1>{person.name}</h1>
完整代码
import React, { Fragment } from ‘react‘; import ReactDOM from ‘react-dom‘; const msg = "你们好呀"; const isBoy = false; const format = (msg) => { return ‘---‘ + msg + ‘---‘; } const person = { name: "沙和尚" }; const App = () => { return ( <Fragment> <h1>我就是jsx</h1> {/* 数字 */} <h1>{1 + 1}</h1> {/* 字符串 */} <h1>{‘hello world‘}</h1> {/* bool类型 */} <h1>{isBoy}</h1> {/* 使用变量 */} <h1>{msg}</h1> {/* 3目运算符 */} <h1>{isBoy ? "男生" : "女生"}</h1> {/* 调用方法 */} <h1>{format(msg)}</h1> {/* 使用对象 */} <h1>{person.name}</h1> </Fragment> ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
4.3.JSX嵌套JSX JSX循环
按照这个思路去理解即可
- index.js文件可以直接写标签入<h1></h1>
- 在标签中可以通过{}直接写js如<h1>{‘你们好’}</h1>
- 既然1中的js可以直接写标签,那么{}中的js也可以直接写标签
如下所示:
import React from ‘react‘; import ReactDOM from ‘react-dom‘; const msg = "今天天气不错"; const App = () => { return ( <div > { <div> <h1>我也是大头 {msg} </h1> <h1>我也是大头 {msg} </h1> </div> } </div> ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
加强版本,必须要掌握
import React from ‘react‘; import ReactDOM from ‘react-dom‘; const list = [‘苹果‘, ‘香蕉‘, ‘雪梨‘, ‘西瓜‘]; const App = () => { return ( <div > { <div> { list.map(function (v) { return ( <h1 key={v}>{v}</h1> ) }) } </div> } </div> ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
终极版 最常用
import React from ‘react‘; import ReactDOM from ‘react-dom‘; const list = [‘苹果‘, ‘香蕉‘, ‘雪梨‘, ‘西瓜‘]; const App = () => { return ( <div > { <div> { list.map(v => <h1 key={v}>{v}</h1>) } </div> } </div> ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
4.4.JSX注释
{ // 这里是单行注释 } { /* 这里是多行注释 这里是多行注释 这里是多行注释 这里是多行注释 */ }
4.5.JSX标签属性
jsx标签上可以设置绝大部分和以前html标签一样的属性,如checked、图片的src
除此之外
1.html的class属性改为className
<div className="redCls">大头大头</div>
2.html中label标签的for属性改为htmlFor
<label htmlFor="inp">
点我点我
<input id="inp" type="text" />
</label>
3.标签中的自定义属性使用data
<div data-index={‘hello‘} >自定义属性</div>
4.渲染html字符串使用dangerouslySetInnerHTML属性
<li dangerouslySetInnerHTML={{__html:"<i>打我呀</i>"}}></li>
5.bool类型的值可以这样用
<input type="checkbox" checked={true} />
6.当属性太多了,可以使用...拓展运算符
const props={ className:"redCls", "data-index":5 } <div {...props}>展开属性</div>
4.6.JSX的行内样式
JSX可以像传统的HTML标签一样添加行内样式,不同的是,要通过对象的方式来实现。并且属性名是以驼峰命名。
import React from ‘react‘; import ReactDOM from ‘react-dom‘; import "./index.css"; const App = () => { return ( <div style={{ color: ‘yellow‘, fontSize: "50px", "backgroundColor": ‘blue‘ }} > 颜色好好看呀 </div> ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
4.7.JSX创建组件的本质(了解即可)
JSX俗称 语法糖,提供了一种更好使用的语法让我们使用,其本质是调用React.createElement实现的
React.createElement,接收3个参数
- 标签名 如 “div”
- 标签上的属性,如{className: "redCls"}
- 文本内容或者另一个React.createElement对象或者React.createElement数组
import React from ‘react‘; import ReactDOM from ‘react-dom‘; import "./index.css"; const parentProps = { className: "redCls", "data-index": 100 } const App = () => { return React.createElement( "div", parentProps, [ React.createElement( "span", null, "你们好呀" ), React.createElement( "span", null, "你们好呀" ) ] ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
5.组件的创建
在React中,组件分为两种,类组件和函数式组件
- 简单功能使用函数式组件
- 复杂功能使用类组件
- 组件名都必须大写
5.1.类组件
- 使用es6创建class的方式来实现一个组建类
- 首字母要大写
- 要继承React中的Component类
- 必须实现render函数,函数内返回标签
- 组件有自己的state和生命周期
import React,{Component} from ‘react‘; import ReactDOM from ‘react-dom‘; import "./index.css"; class App extends Component { render() { return ( <div> hello </div> ) } } ReactDOM.render(<App />, document.getElementById(‘root‘))
5.2.函数式组件
也叫做无状态组件
简单功能组件可以使用函数式组件,性能更高。
函数式组件其实就是一个函数,只不过函数内部要返回对应的标签
- 首字母要大写
- 函数内返回标签
import React from ‘react‘; import ReactDOM from ‘react-dom‘; import "./index.css"; // 这个就是函数式组件 const App = () => { return ( <div>这个就是一个简单的函数式组件</div> ) } ReactDOM.render(<App />, document.getElementById(‘root‘))
5.3.小结
- 函数式组件性能更高,因为没有生命周期
- 函数式组件更方便进行测试
- 能不用类组件就不要用类组件
- 当要使用state时,就要使用类组件
6.状态和属性
在React中,状态和属性都可以实现数据动态化,我们现在开始这两个知识
6.1.状态state
在react中,内部组件的数据是通过state来实现和管理
- 可以理解为state就是vue中的data
- 函数式组件没有自己的state
我们之前使用变量,都是脱离了组件本身,正确来说,组件自身是应该具有私有和独立的数据(状态)的,这个私有的数据和状态就叫做state,以后,只要说到数据的状态那么就是指state
6.1.1.state的声明和使用
在类组件中,state的声明分为两种方式
1.类属性的方式声明
class Person extends Component { // 1 声明 state state = { date: "2008", msg: "大头大头下雨不愁" } render() { return ( <div> {/* 2 使用state */} <h1>{this.state.date}</h1> <h2>{this.state.msg}</h2> </div> ) } }
2.构造函数中声明
class Person extends Component { // 1 构造函数中 声明 state constructor() { // 1.1 必须在this之前调用super()方法 super(); this.state = { date: "2008", msg: "大头大头下雨不愁" } } render() { return ( <div> {/* 2 使用state */} <h1>{this.state.date}</h1> <h2>{this.state.msg}</h2> </div> ) } }
6.1.2.state的赋值
state的赋值方式通过this.setState方式来实现
需要注意的是,不能使用this.state.date=100 直接修改
class Person extends Component { state = { date: 2008 } // 2 事件的声明 要使用箭头函数 handleClick = () => { // 3 获取state中的日期 let { date } = this.state; // 4 修改state中的日期 this.setState({ date: date + 1 }); } render() { return ( // 1 绑定事件 事件名必须驼峰命名 <div onClick={this.handleClick}> <h1>{this.state.date}</h1> </div> ) } }
6.1.3.state的赋值是异步的
react为了优化性能,将state的赋值代码改成异步的方式,为了避免反复的设置state而引发的性能损耗问题。
看看下面打印的值
class Person extends Component { state = { date: 2008 } handleClick = () => { let { date } = this.state; // 1 修改state中的日期 增加 1000 this.setState({ date: date + 1000 }); // 2 看看这个date是多少 console.log(this.state.date); } render() { return ( <div onClick={this.handleClick}> <h1>{this.state.date}</h1> </div> ) } }
有时候,我们希望在一设置值的时候,就希望马上得到最新的state的值,那么可以将代码改为下列的写法,给setState添加一个回调函数,回调中可以获取到修改后的state的值
class Person extends Component { state = { date: 2008 } handleClick = () => { let { date } = this.state; // 添加一个回调函数 this.setState({ date: date + 1000 }, () => { // date的值为 3008 console.log(this.state.date); }); } render() { return ( <div onClick={this.handleClick}> <h1>{this.state.date}</h1> </div> ) } }
有时候,setState还可以接收一个函数,函数内可以实时获取state中的值,不存在延迟。
this.setState(preState => { console.log("上一次的state", preState.date); return { date: preState.date + 1000 } }) this.setState(preState => { console.log("上一次的state", preState.date); return { date: preState.date + 1 } })
6.2.属性props
props意思是属性,一般存在父子组件中,用于父向子传递数据。
子组件不能修改接受到的props值
6.2.1.初体验
1.声明一个类组件HomeTop父组件的数据通过this.props来获取
class HomeTop extends Component { render() { return ( <h1>屋顶的颜色是 {this.props.acolor} 尺寸 {this.props.asize}</h1> ) } }
2.声明一个函数式组件HomeFotter,父组件传递的数据 需要在函数的形参props上接收
const HomeFooter = (props) => { return <h1>屋底的颜色是 {props.bcolor} 尺寸 {props.bsize}</h1> }
3.声明父组件,并在标签上通过属性的方式进行传递数据
class Home extends Component { state = { color: "blue", size: 100 } render() { return ( <div> <HomeTop acolor={this.state.color} asize={this.state.size} ></HomeTop> <HomeFooter bcolor={this.state.color} bsize={this.state.size} ></HomeFooter> </div> ) } }
4.需要注意的是父组件中的变量名是color,size而HomeTop和HomeFotter中修改了一下变量名,分别是acolor,asize和bcolor,bsize。
完整代码
import React, { Component } from ‘react‘; import ReactDOM from ‘react-dom‘; class HomeTop extends Component { render() { return ( <h1>屋顶的颜色是 {this.props.acolor} 尺寸 {this.props.asize}</h1> ) } } const HomeFooter = (props) => { return <h1>屋底的颜色是 {props.bcolor} 尺寸 {props.bsize}</h1> } class Home extends Component { state = { color: "blue", size: 100 } render() { return ( <div> <HomeTop acolor={this.state.color} asize={this.state.size} ></HomeTop> <HomeFooter bcolor={this.state.color} bsize={this.state.size} ></HomeFooter> </div> ) } } ReactDOM.render(<Home />, document.getElementById(‘root‘))
6.2.2.类组件构造函数中的props
当想要在类组件的构造函数中,获取到props时,需要如下使用:
constructor(props) {
super(props);
console.log(props);
}
6.2.3.props默认值
当父元素没有传递props属性时,子组件可以指定一个默认props属性值来使用。
通过 组件名.defaultProps 来指定
import React from ‘react‘; import ReactDOM from ‘react-dom‘; let HomeNav = (props) => { return <h1> 导航为 {props.color} </h1> } // 指定一个默认属性 HomeNav.defaultProps = { color: "yellow" } class Home extends Component { state = { color: "blue" } render() { return ( <div> <HomeNav></HomeNav> </div> ) } } ReactDOM.render(<Home />, document.getElementById(‘root‘))
6.2.4.props类型检验
在一些要求代码更为严格的项目中,父组件传递数据的格式,必须和子组件要求的格式保持一致,否则就认为代码出错。
如子组件要求的是数字类型(100),而父组件传递的是字符串类型(“100”)。
这个需求可以通过react中的props类型检验来完成。
自React v15.5起,react.PropTypes已移入另一个包中。请使用prop-types库代替
6.2.4.1.安装prop-types
yarn add prop-types --dev
引入
import PropTypes from ‘prop-types‘;
6.2.5.使用
import React, { Component } from ‘react‘; import ReactDOM from ‘react-dom‘; // 1 引入 prop-types import PropTypes from ‘prop-types‘; let HomeNav = (props) => { return <h1> 导航为 {props.color} 数量为 {props.nums} </h1> } // 2 指定要求接收的数据格式 HomeNav.propTypes ={ color:PropTypes.string, nums:PropTypes.number } class Home extends Component { state = { color: "blue", nums:100 } render() { return ( <div> <HomeNav {...this.state}></HomeNav> </div> ) } } ReactDOM.render(<Home />, document.getElementById(‘root‘))
6.2.6.props插槽props.children
props.children可以实现类似Vue中的插槽功能(slot)
6.2.6.1.子组件
let HomeNav = (props) => { return ( <div> <div>标题</div> <div>{props.children}</div> </div> ) }
6.2.6.2.父组件
class Home extends Component { render() { return ( <div> <HomeNav {...this.state}> {/* 这里放动态插入的内容 */} <div>小标题你</div> </HomeNav> </div> ) } }
6.2.6.3.完整代码
import React, { Component } from ‘react‘; import ReactDOM from ‘react-dom‘; import PropTypes from ‘prop-types‘; let HomeNav = (props) => { return ( <div> <div>标题</div> <div>{props.children}</div> </div> ) } class Home extends Component { render() { return ( <div> <HomeNav {...this.state}> {/* 这里放动态插入的内容 */} <div>小标题</div> </HomeNav> </div> ) } } ReactDOM.render(<Home />, document.getElementById(‘root‘))
6.3.state和props对比
相同
- 二者都作为React内更新视图的依据,只有他们变化时,React才会进行相应的更新
- 二者都不可以通过直接赋值的方式更新
不同
- 更新方式不同:state通过setState方法更新(只能在组件内部更新),props则通过传入的值实现(组件内不可变)。
- state只维护组件内部的状态,props让外部维护组件的状态。
总结:尽量少用state,尽量多用props,这样既能提高组件的可复用性,又能降低维护成本。
7.事件
React元素的事件处理和DOM元素的很相似,但是有一点语法上的不同:
- React事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用JSX语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
7.1.传统HTML绑定事件
<button onclick="activateLasers()">
Activate Lasers
</button>
7.2.React中
<button onClick={this.handleClick}> Activate Lasers </button>
7.3.事件中的this
观察以下的this值 它是undefined
import React, { Component } from ‘react‘; import ReactDOM from ‘react-dom‘; class Home extends Component { state = { msg: "大家好呀" } handleClick() { // undefined console.log(this); } render() { return ( <div> <div onClick={this.handleClick} >小标题</div> </div> ) } } ReactDOM.render(<Home />, document.getElementById(‘root‘))
因为在react中,绑定事件不是原生HTML的dom元素,onClick只是react帮我们做的一个中间的映射,那么他在处理事件的时候,是不会处理this的指向的,我们需要手动处理这个this
7.3.1.处理方式
1.绑定事件的时候使用bind来锁定this 代码丑陋,不推荐
<div onClick={this.handleClick.bind(this)} >小标题</div>
2.在构造函数中使用bind修改this执行(推荐)
import React, { Component } from ‘react‘; import ReactDOM from ‘react-dom‘; class Home extends Component { state = { msg: "大家好呀" } constructor() { super(); // 重新绑定this this.handleClick = this.handleClick.bind(this); } handleClick() { console.log(this); } render() { return ( <div> <div onClick={this.handleClick} >小标题</div> </div> ) } } ReactDOM.render(<Home />, document.getElementById(‘root‘))
3.将事件的执行,改成箭头函数的方式(推荐)
import React, { Component } from ‘react‘; import ReactDOM from ‘react-dom‘; class Home extends Component { state = { msg: "大家好呀" } // 修改为箭头函数的方式 handleClick = () => { console.log(this); } render() { return ( <div> <div onClick={this.handleClick} >小标题</div> </div> ) } } ReactDOM.render(<Home />, document.getElementById(‘root‘))
7.4.事件传参
执行类似以前HTML的DOM事件传参一样的功能
<button onclick="show(‘大家好‘)"></button>
React中的写法为:
不推荐,容易导致意外情况(BUG)
<button onClick={() => { this.handleClick(‘red‘) }}>红色</button>
推荐写法:
<button onClick={ this.handleClick.bind(this,‘red‘) }>红色</button>
以上是关于React基础知识的主要内容,如果未能解决你的问题,请参考以下文章
javascript 用于在节点#nodejs #javascript内设置react app的代码片段
[React Testing] Use Generated Data in Tests with tests-data-bot to Improve Test Maintainability(代码片段