React大纲
课程教学目标
- React基本语法
- React组件通信
- State
- Redux
- React-Redux
React基础
脚手架
安装
npm isntall -g create-react-app
查看版本
create-react-app --version
创建项目
create-react-app my-app
进入项目目录
cd my-app
安装必要依赖
npm install
运行
npm start
开发者工具
React-developer-tools使用和安装
React的组件
官网地址:https://react.docschina.org
CDN方式引入
开发环境
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js">
生产环境
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js">
在网页中使用React
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
const element =<h1>Hello, world!</h1>;
ReactDOM.render(
element,
document.getElementById('example')
);
</script>
</body>
</html>
JSX 语法
React 使用 JSX 来替代常规的 JavaScript。
JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
我们不需要一定使用 JSX,但它有以下优点:
- JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
- 它是类型安全的,在编译过程中就能发现错误。
- 使用 JSX 编写模板更加简单快速。
元素是构成 React 应用的最小单位,JSX 就是用来声明 React 当中的元素。JSX 是在 JavaScript 内部实现的,与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。
基础示例
const element = <h1 className="foo">Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
使用表达式
ReactDOM.render(
<div>
<h1>{1+1}</h1>
</div>
,
document.getElementById('example')
);
数组
JSX 允许在模板中插入数组,数组会自动展开所有成员:
var arr = [
<h1>标题</h1>,
<p>内容</p>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
创建组件
函数组件
function HelloMessage(props) {
return <h1>Hello World!</h1>;
}
const element = <HelloMessage />;
ReactDOM.render(
element,
document.getElementById('example')
);
Class组件
class Welcome extends React.Component {
render() {
return <h1>Hello World!</h1>;
}
}
函数组件和class组件的区别
无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props
。
React是单项数据流,父组件改变了属性,那么子组件视图会更新。
属性 props
是外界传递过来的,状态 state
是组件本身的,状态可以在组件中任意修改,组件的属性和状态改变都会更新视图。
-
使用class创建的组件,有自己的私有数据(this.state)和生命周期
-
使用function创建的组件,只有props,没有自己的私有数据和生命周期函数。
-
用构造函数创建的组件叫无状态组件,用class创建的组件叫有状态组件(受控组件和非受控组件)
使用范围
如果一个组件有自己的私有数据,则推荐使用class创建有状态组件;
如果一个组件不需要私有的数据,则推荐使用,无状态组件。
React组件的三大属性
state 属性
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
React 里,只需更新组件的 state
,然后根据新的state
重新渲染用户界面(不要操作 DOM)。
state
是私有的,并且完全受控于当前组件,只有Class
组件采用有state属性。
class Clock extends React.Component {
//添加一个 class 构造函数,然后在该函数中为 this.state 赋初值
constructor(props) {
//Class 组件应该始终使用 props 参数来调用父类的构造函数。
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
props属性
props
是不可变的,而 state 可以根据与用户交互来改变。\定义 state 来更新和修改数据。 组件只能通过 props 来传递数据和接受数据。
function HelloMessage(props) {
return <h1>Hello {props.name}!</h1>;
}
const element = <HelloMessage name="Runoob"/>;
ReactDOM.render(
element,
document.getElementById('example')
);
state属性和props属性的区别
-
组件中的props和state/data之间的区别
-
props的数据都是从外界传递过来的
-
state/data中的数据,都是组件私有的;(通过ajax获取的数据一般都是私有数据)
-
props中的数据都是只读的,不能重新赋值的。
-
state/data中的数据,都是可读可写的。
refs属性值
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例
class MyComponent extends React.Component {
handleClick() {
// 使用原生的 DOM API 获取焦点
this.refs.myInput.focus();
}
render() {
// 当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
return (
<div>
<input type="text" ref="myInput" />
<input
type="button"
value="点我输入框获取焦点"
onClick={this.handleClick.bind(this)}
/>
</div>
);
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
React 进阶
React组件通信
React数据流动是单向的,
父传子
父组件通过props向子组件传递数据
子组件
import React from 'react';
import PropTypes from 'prop-types';
export default function Child({ name }) {
return <h1>Hello, {name}</h1>;
}
Child.propTypes = {
name: PropTypes.string.isRequired,
};
父组件
import React, { Component } from 'react';
import Child from './Child';
class Parent extends Component {
render() {
return (
<div>
<Child name="Sara" />
</div>
);
}
}
export default Parent;
数据类型校验和默认值
默认值
组件使用props传递数据,同时可以设置props的默认值,如果父组件没有向子组件传递数据,可以使用默认值:
import React from 'react';
import PropTypes from 'prop-types';
export default function Child({ name }) {
return <h1>Hello, {name}</h1>;
}
Child.propTypes = {
name: PropTypes.string.isRequired,
};
Child.defaultProps={
name:"world"
}
或者在有状态组件中,可以写成静态属性,但是必须使用像 transform-class-properties 的 Babel 转换工具,才可以在 React 组件类中声明 defaultProps
作为静态属性。此语法提案还没有最终确定,需要进行编译后才能在浏览器中运行。
import React from 'react';
import PropTypes from 'prop-types';
export default Class Child extends React.Component {
static defaultProps={
name:"world"
}
constructor(props){
super(props);
}
render() {
return (
return <h1>Hello, {this.props.name}</h1>;
);
}
return <h1>Hello, {name}</h1>;
}
数据类型校验
通过类型检查捕获大量错误。对于某些应用程序来说,你可以使用 Flow 或 TypeScript 等 JavaScript 扩展来对整个应用程序做类型检查。但即使你不使用这些扩展,React 也内置了一些类型检查的功能。要在组件的 props 上进行类型检查,你只需配置特定的 propTypes
属性.
注意:
自 React v15.5 起,
React.PropTypes
已移入另一个包中。请使用prop-types
库 代替。
安装
npm install --save prop-types
使用
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
PropTypes
提供一系列验证器,可用于确保组件接收到的数据类型是有效的。出于性能方面的考虑,propTypes
仅在开发模式下进行检查。
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode: PropTypes.node,
// 一个 React 元素。
optionalElement: PropTypes.element,
// 一个 React 元素类型(即,MyComponent)。
optionalElementType: PropTypes.elementType,
// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),
// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// 一个对象可以是几种类型中的任意一个类型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 可以指定一个数组由某一类型的元素组成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// 可以指定一个对象由某一类型的值组成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// 可以指定一个对象由特定的类型值组成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,
// 任意类型的数据
requiredAny: PropTypes.any.isRequired,
// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
defaultProps
用于确保 this.props.name
在父组件没有指定其值时,有一个默认值。propTypes
类型检查发生在 defaultProps
赋值后,所以类型检查也适用于 defaultProps
。
子传父
- 利用回调函数
- 利用自定义事件机制
示例
实现在子组件中点击隐藏组件按钮可以将自身隐藏的功能
子组件
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class Child extends Component {
static propTypes = {
hideConponent: PropTypes.func.isRequired,
}
render() {
return (
<div>
哈哈,我是Child
<button onClick={this.props.hideConponent}>隐藏Child组件</button>
</div>
);
}
}
export default List3;
父组件
import React, { Component } from 'react';
import Child from './components/Child';
export default class App extends Component {
constructor(...args) {
super(...args);
this.state = {
isShowList3: false,
};
}
showConponent = () => {
this.setState({
isShowList3: true,
});
}
hideConponent = () => {
this.setState({
isShowList3: false,
});
}
render() {
return (
<div>
<button onClick={this.showConponent}>显示Child组件</button>
{
this.state.isShowList3 ?
<Child hideConponent={this.hideConponent} />
:
null
}
</div>
);
}
}
兄弟组件通信
也叫非嵌套组件通信。
利用二者共同父组件进行通信,但是采用组件间共同的父级来进行中转,会增加子组件和父组件之间的耦合度,如果组件层次较深的话,找到二者公共的父组件不是一件容易的事。
推荐使用自定义事件的方式。
安装events依赖
npm install events --save
新建event.js文件并向外提供一个事件对象,供通信时使用:
import { EventEmitter } from "events";
export default new EventEmitter();
跨组件通信(context)
State
setState()
内部状态
合并更新
异步更新
This指向
组件受控
###组件的生命周期
Todolist
组件拆分
实现添加列表、列表的显示
列表的编辑
过滤
清除所选
react-router-dom
介绍
安装
内置组件
4.2.1 BrowserRouter★★★★★
4.2.2 HashRouter★★★★★
4.2.3 Route★★★★★
4.2.4 Redirect★★★★★
4.2.5 Link★★★
4.2.6 Navlink★★★★★
4.2.7 Switch★★★
4.3 *嵌套路由*
4.3.1 嵌套路由的配置★★★★★
4.4 *路由传参*
4.4.1 参数传递★★★★★
5.1 *介绍*
5.1.1 介绍★★★
5.1.2 安装★★★
5.2 *R********edux的运行流程*
5.2.1 redux的运行流程★★★★★
5.3 *R********edux的核心概念*
5.3.1 Action★★★
5.3.2 Reducer★★★
5.3.3 Store★★★
5.4 *核心api*
5.4.1 createStore★★★
5.4.2 combinereducers★★★
5.4.3 applyMiddleware★★★
5.4.4 getState★★★
5.4.5 Subscribe★★★
5.4.6 Dispatch★★★
5.4.7 unsubscribe★★★
5.4.8 中间件redux-thunk★★★
6.1 *简介*
6.1.1 react-redux的概念★★★
6.1.2 安装及使用★★★
6.2 *R********eact-redux的概念*
6.2.1 react-redux的概念★★★
6.2.2 安装及使用★★★
6.3 *核心关键字*
6.3.1 Provider★★★
6.3.2 Connect★★★
6.4 *核心关键字*
6.4.1 mapStateToProps★★★
6.4.2 mapDispatchToProps★★★