react学习笔记

一、简介

React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。

二、安装

1
2
#安装脚手架Create React App
$ npm install -g create-react-app

如果下载比较慢,建议替换淘宝源:

1
2
3
4
#换源
$ npm config set registry https://registry.npm.taobao.org
#配置后通过以下方法验证是否成功
$ npm config get registry

三、创建项目

1. 脚手架创建react工程

1
2
#创建项目
$ create-react-app my-app

删除掉非必须的文件后,留下如下目录结构的文件:

1
2
3
4
5
6
7
8
9
.
├── package-lock.json
├── package.json
├── public
│   ├── index.html
│   └── manifest.json
└── src
├── App.js
└── index.js

2. 编辑相关文件

manifest.json

1
2
3
4
5
6
7
8
9
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

index.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
</head>
<body>
<div id="root"></div>
</body>
</html>

index.js

1
2
3
4
5
6
7
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

//将<App />渲染到index.html的<div id="root"></div>里,其中<App/>就是jsx语法
//解读jsx:遇到<>则安装html解析,遇到{}则按照js解析
ReactDOM.render(<App />, document.getElementById("root"));

App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from "react";
const msg = "React";
/**
* 组件App
*/
function App() {
return (
<div>
{/*注释...... */}
Hello {msg}
</div>
);
}

export default App;

3. 运行项目

1
2
$ cd my-app
$ npm start

四、React组件

Father.jsx

组件文件后缀可以是.js,也可以是.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import React from "react";
const msg = "React";
/**
* 函数式组件
*/
// eslint-disable-next-line
function AppFunction() {
return <div>Hello {msg}</div>;
}

/**
* 类组件
*/
// eslint-disable-next-line
class AppClass extends React.Component {
//渲染函数
render() {
return <div>Hello {msg}</div>;
}
}

/**
* 复合组件:组件中又有其他的组件,复合组件中既可以有类组件又可以有函数组件
*/
function ChildcomApp(props) {
console.log(props)
let age = props.age
return (
<div style={childrencss}>
<h3>Childcom组件</h3>
{age}
</div>
)
}
class FatherApp extends React.Component {
render() {
console.log(this)
return (
<div style={fathercss}>
<h3>Father组件</h3>
<h4>hello:{this.props.name}</h4>
<ChildcomApp age={this.props.age} />
</div>
)
}
}
/**
* css样式
*/
let childrencss = {
width: "50%",
backgroundColor: "red"
}
let fathercss = {
width: "50%",
backgroundColor: "skyblue"
}

export default FatherApp;

index.js

1
2
3
4
5
import React from "react";
import ReactDOM from "react-dom";
import FatherApp from "./FatherApp";

ReactDOM.render(<FatherApp name="qcmoke" age="18" />, document.getElementById("root"));

image-20200705004332651

五、组件状态state

state 是组件的当前状态,可以把组件简单看成一个“状态机”,根据状态 state 呈现不同的 UI 展示。

一旦状态(数据)更改,组件就会自动调用 render 重新渲染 UI,这个更改的动作会通过 this.setState 方法来触发。

StateApp.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import React from "react";

export default class StateApp extends React.Component {

//组件的构造函数,如果要在构造函数中获取传值,可以在参数列表中加props
constructor(props) {
super(props);
//组件的状态(数据)
this.state = {
count: 1
};
}


clickEvent(e) {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
{/**state是私有属性,只能读取不能直接修改 state(直接去改变状态,组件将不会感知到,更不会因为状态的改变而重新渲染),但可通过组件的setState()方法修改 */}
<h2>It is {this.state.count}.</h2>
{/*需要在事件中获取组件的this,需要bind(this) */}
<button onClick={this.clickEvent.bind(this)}>click2</button>
{/*如果不使用bind(this),可以使用箭头函数解决 */}
<button onClick={() => {
this.setState({
count: this.state.count + 1
})
}}>click2</button>
</div>
);
}
}

index.js

1
2
3
4
5
import React from "react";
import ReactDOM from "react-dom";
import StateApp from "./StateApp";

ReactDOM.render(<StateApp />, document.getElementById("root"));

六、生命周期

img

LifeApp.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import React from "react";

export default class LifeApp extends React.Component {

constructor(props) {
super(props);
this.state = { count: 1 };
}

//(1)组件将要挂载时触发的函数
componentWillUnmount() {
console.log("componentWillUnmount");
}

//(2)组件挂载完成时触发的函数
componentDidMount() {
console.log("componentDidMount");
}

//(3)是否要更新数据时触发的函数
shouldComponentUpdate() {
return true;
}

//(4)数据在改变之前执行
componentWillUpdate() {
console.log("componentWillUpdate");
}

//(5)数据在改变之后执行
componentDidUpdate() {
console.log("componentDidUpdate");
}

//(6)组件将要销毁时触发的函数
componentWillUnmount() {
console.log("componentWillUnmount");
}

//(7)父组件中改变了props传值时触发的函数
componentWillReceiveProps() {
console.log("componentWillReceiveProps");
}

render() {
return (
<div>
{/**state是私有属性,只能读取不能直接修改 state(直接去改变状态,组件将不会感知到,更不会因为状态的改变而重新渲染),但可通过组件的setState()方法修改 */}
<h2>It is {this.state.count}.</h2>
<button onClick={() => {
this.setState({ count: this.state.count + 1 })
}}>click</button>
</div>
);
}
}

index.js

1
2
3
4
5
import React from "react";
import ReactDOM from "react-dom";
import LifeApp from "./LifeApp";

ReactDOM.render(<LifeApp />, document.getElementById("root"));

七、组件传值

以下示例包含组件间的父传子和子传父两种情况。

FatherApp.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React from "react";
import ChildcomApp from "./ChildcomApp"

export default class FatherApp extends React.Component {
constructor(props) {
super(props)
this.state = {
childData: "child",
fatherData: "father"
};
}

/**
* 子传父的回调函数
*/
callback = (data) => {
this.setState({ fatherData: data })
}
render() {
return (
<div style={fathercss}>
<h3>{this.state.fatherData}</h3>
{/**使用子组件并传值或者函数给子组件 */}
<ChildcomApp childData={this.state.childData} callback={this.callback} />
</div>
)
}
}

let fathercss = {
width: "50%",
backgroundColor: "skyblue"
}

ChildcomApp.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from "react";

export default class ChildcomApp extends React.Component {

render() {
return (
<div style={childrencss}>
{/**获取父组件的传值 */}
<div>{this.props.childData}</div>
<button onClick={() => {
//调用父组件的回调函数从而传值给父组件
this.props.callback("hi father")
}}>子传父</button>
</div>
)
}
}
let childrencss = {
width: "50%",
backgroundColor: "red"
}

index.js

1
2
3
4
5
import React from "react";
import ReactDOM from "react-dom";
import FatherApp from "./FatherApp";

ReactDOM.render(<FatherApp />, document.getElementById("root"));

八、事件处理

React 元素的事件处理和 DOM 元素类似。但是有一点语法上的不同:

  • React 事件绑定属性的命名采用驼峰式写法,而不是小写。
  • 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)

HTML 通常写法是:

1
2
3
4
<!--此处的onclick是小写的,传入的函数写法是一个字符串-->
<button onclick="activateLasers()">
激活按钮
</button>

React 中写法为:

1
2
3
4
<!--此处的onClick是驼峰式,传入的函数写法是函数本身-->
<button onClick={activateLasers}>
激活按钮
</button>

事件处理案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import React from "react";
import ReactDOM from "react-dom";

class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
// handleClick1绑定this是必要的,这样this才能在回调函数中使用
this.handleClick1 = this.handleClick1.bind(this);
}

handleClick1() {
this.setState((prevState) => ({
isToggleOn: !prevState.isToggleOn,
}));
}

//使用箭头函数来定义事件的函数(e可省略)
handleClick2 = (e) => {
console.log(e);
};

//事件对象e要放在最后(e可省略)
handleClick3(msg, e) {
console.log(msg, e);
}

render() {
return (
<div>
{/*事件的函数需要绑定当前组件的this(否则在事件函数中this的值会是 undefined),可以直接在调用时直接绑定,也可以在组件的构造函数中绑定。
如果不想绑定this,那么也可以使用箭头函数来定义事件的函数。*/}
<button onClick={this.handleClick1}>
{this.state.isToggleOn ? "ON" : "OFF"}
</button>
<button onClick={this.handleClick2}>btn2</button>

{/* 向事件处理程序传递参数(两种方式) */}
<button onClick={this.handleClick3.bind(this, "hello")}>btn3_1</button>
<button onClick={(e) => this.handleClick3("hello", e)}>btn3_2</button>
</div>
);
}
}

ReactDOM.render(<Toggle />, document.getElementById("root"));

九、条件渲染

React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import React from "react";
import ReactDOM from "react-dom";

function WarningBanner(props) {
if (!props.warn) {
//返回 null即可阻止组件渲染
return null;
}
return <div>警告!</div>;
}

class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {
active: true,
showWarning: true,
};
}
render() {
return (
<div>
{/* true && expression 总是返回 expression,而 false && expression 总是返回 false.如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它 */}
{this.state.active && <div>active</div>}

<WarningBanner warn={this.state.showWarning} />
<button
onClick={() => {
this.setState((prevState) => ({
showWarning: !prevState.showWarning,
}));
}}
>
{/* 三元运算符 */}
{this.state.showWarning ? <span>隐藏</span> : <span>显示</span>}
</button>
</div>
);
}
}

ReactDOM.render(<Toggle />, document.getElementById("root"));

十、列表 & Keys

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from "react";
import ReactDOM from "react-dom";

const posts = [
{ id: 1, title: "Hello World", content: "Welcome to learning React!" },
{ id: 2, title: "Installation", content: "You can install React from npm." },
];

function Blog(props) {
const content = props.posts.map((post) => (
/* 元素的 key 在他的兄弟元素之间应该唯一。
Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化 */
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
));
return <div>{content}</div>;
}

ReactDOM.render(<Blog posts={posts} />, document.getElementById("root"));

十一、组件插槽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import React from "react";
import ReactDOM from "react-dom";

class Child extends React.Component {
render() {
let header, main, footer;
this.props.children.forEach((item, index) => {
switch (item.props['data-position']) {
case "header":
header = item
break;
case "main":
main = item
break;
case "footer":
footer = item
break;
default:
break;
}
})
return (
<div>
<h2>组件插槽</h2>
<div>{header}</div>
<div>{main}</div>
<div>{footer}</div>
</div>
)
}
}

class Parent extends React.Component {
render() {
return (
<Child>
{/* 传给子组件插槽的内容 */}
<h1 data-position="header">header</h1>
<h1 data-position="main">main</h1>
<h1 data-position="footer">footer</h1>
</Child>
)
}
}


ReactDOM.render(<Parent></Parent>, document.getElementById("root"));

十二、路由

安装依赖

1
$ npm install react-router-dom --save

Home.jsx

1
2
3
4
5
6
import React from "react";
export default class Home extends React.Component {
render() {
return <div>欢迎来到主页</div>
}
}

About.jsx

1
2
3
4
5
6
import React from "react";
export default class About extends React.Component {
render() {
return <div>关于我......</div>
}
}

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from "react";
import ReactDOM from "react-dom";

import Home from "./Home"
import About from "./About"

//hash模式
// import { HashRouter as Router, Link, Route } from "react-router-dom";

//history模式
import { BrowserRouter as Router, Link, Route } from "react-router-dom";

class App extends React.Component {
render() {
return (
<div>
<Router>
{/* <Router basename="/admin"> basename可以设定所有路由前缀*/}
<div className="nav">
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</div>
<Route path="/" exact component={Home}></Route>{/* exact表示严格匹配模式 */}
<Route path="/about" exact component={About}></Route>
</Router>
</div>
);
}
}

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

十三、状态管理Redux

1. redux工作流程

img

2. 核心概念

  • action:

    标识要执行行为的对象(同步action)。它的值也可以是函数(异步action),但需要引入redux-thunk

    包含2个方面的属性:

    type: 标识属性, 值为字符串, 唯一, 必要属性

    xxx(一般起名为data): 数据属性, 值类型任意, 可选属性

  • reducer
    为一个函数,根据老的state和指定的action, 返回一个新的state,不能修改老的state

  • store

    state,actionreducer联系在一起的对象,是redux最核心的管理对象。内部管理着statereducer,提供方法有:

    getState(): 得到state
    dispatch(action): 分发action, 触发reducer调用, 产生新的state
    subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

3. 相关API

1
2
3
redux中包含: createStore(), applyMiddleware(), combineReducers()
store对象: getState(), dispatch(), subscribe()
react-redux: <Provider>, connect()()

4. 安装依赖

1
$ npm install redux --save

5. 使用案例

action-types.js

1
2
3
4
5
/*
action对象的type常量名称模块
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

actions.js

1
2
3
4
5
6
7
/*
action creator模块
*/
import {INCREMENT, DECREMENT} from './action-types'

export const increment = number => ({type: INCREMENT, number})
export const decrement = number => ({type: DECREMENT, number})

reducers.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { INCREMENT, DECREMENT } from "./action-types";

/**
* 定义一个reducer函数
* 根据老的state和指定action, 处理返回一个新的state
* @param {*} state
* @param {Object} action
*/
export const counter = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
// 返回一个新的状态,不能修改原来的状态
return state + action.number;
case DECREMENT:
return state - action.number;
default:
return state;
}
};

App.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from "react";
import * as actions from "./redux/actions";

export default class App extends React.Component {
render() {
return (
<div>
<h1>
{/* getState(): 得到state */}
{this.props.store.getState()}
</h1>
<p>
{/* dispatch(action):分发action, 触发reducer调用, 产生新的state */}
<button onClick={() => this.props.store.dispatch(actions.increment(1))}>increment</button>
<button onClick={() => this.props.store.dispatch(actions.decrement(1))}>decrement</button>
</p>
</div>
)
}
}

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { counter } from "./redux/reducers";
import App from "./App";

//根据一个reducer创建store对象
const store = createStore(counter);

// 定义渲染根组件标签的函数
const render = () => {
ReactDOM.render(<App store={store} />, document.getElementById("root"));
};

// 初始化渲染
render();

// 注册(订阅)监听, 一旦状态发生改变, 自动重新渲染
store.subscribe(render);

十四、react-redux

专门用来简化react应用中使用redux的插件库。

1. 为什么要使用react-redux?

  • redux与react组件的代码耦合度太高

  • 编码不够简洁

2. 组件分类

React-Redux将所有组件分成两大类:

  • UI组件

    a. 只负责 UI 的呈现,不带有任何业务逻辑

    b. 通过props接收数据(一般数据和函数)

    c. 不使用任何 Redux 的 API

  • 容器组件

    a. 负责管理数据和业务逻辑,不负责UI的呈现

    b. 使用 Redux 的 API

通过React-Redux的使用可以让UI组件中屏蔽redux依赖,从而实现解耦的效果。

3. 安装依赖

1
$ npm install --save react-redux

4. 使用案例

action-types.js

1
2
3
4
5
/*
action对象的type常量名称模块
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

actions.js

1
2
3
4
5
6
7
/*
action creator模块
*/
import {INCREMENT, DECREMENT} from './action-types'

export const increment = number => ({type: INCREMENT, number})
export const decrement = number => ({type: DECREMENT, number})

reducers.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { INCREMENT, DECREMENT } from "./action-types";

/**
* 定义一个reducer函数
* 根据老的state和指定action, 处理返回一个新的state
* @param {*} state
* @param {Object} action
*/
export const counter = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
// 返回一个新的状态,不能修改原来的状态
return state + action.number;
case DECREMENT:
return state - action.number;
default:
return state;
}
};

components/counter.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
UI组件: 不包含任何redux API
a.只负责 UI 的呈现,不带有任何业务逻辑
b.通过props接收数据(一般数据和函数)
c.不使用任何 Redux 的 API
*/
import React from 'react'
import PropTypes from 'prop-types'

export default class Counter extends React.Component {

//声明store管理的状态和action函数,此处接收的内容要和容器组件App中connect()中定义的状态属性名和action函数名一致。
static propTypes = {
count: PropTypes.number.isRequired,
increment: PropTypes.func.isRequired,
decrement: PropTypes.func.isRequired
}

render() {
return (
<div>
<h1>
{this.props.count}
</h1>
<p>
<button onClick={() => this.props.increment(1)}>increment</button>
<button onClick={() => this.props.decrement(1)}>decrement</button>
</p>
</div>
)
}
}

containters/App.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
包含Counter组件的容器组件
a.负责管理数据和业务逻辑,不负责UI的呈现
b.使用 Redux 的 API
*/
// 引入连接函数
import { connect } from 'react-redux'
import { increment, decrement } from "../redux/actions";
import Counter from '../components/counter'

/**
connect():用于包装UI组件从而生成容器组件
由于store是绑定在<Provider/>中的,而不是<Counter/>中,要在Counter组件中接收store里的内容,则需要让store和Counter组件进行关联,
connect()函数就起到了关联的作用。原理就是将Provider中store里的内容解析放到Counter组件中去。
*/
export default connect(
state => ({ count: state }),
{ increment, decrement }
)(Counter)
/*
connect(
    mapStateToprops, //即state对象的属性组成的对象
    mapDispatchToProps //action的相关函数组成的对象
  )(Counter)
*/

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { counter } from "./redux/reducers";
import { Provider } from "react-redux";
import App from "./containters/App";

//根据一个reducer创建store对象
const store = createStore(counter);

/**
* Provider:让所有组件都可以得到state数据
*/
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);

十五、redux异步编程

1. 为什么要使用

因为redux默认是不能进行异步处理的,但实际应用中却可能需要在redux中用到异步处理。

2. 安装依赖

1
$ npm install --save redux-thunk

3. 使用案例

action-types.js

1
2
3
4
5
/*
action对象的type常量名称模块
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

actions.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
action creator模块
同步action调用时返回对象
异步action调用时返回一个函数
*/
import { INCREMENT, DECREMENT } from "./action-types";

export const increment = (number) => ({ type: INCREMENT, number });
export const decrement = (number) => ({ type: DECREMENT, number });

// 异步action creator(返回一个函数)
export const incrementAsync = (number) => {
return (dispatch) => {
//异步处理
setTimeout(() => {
dispatch(increment(number));
}, 2000);
};
};

reducers.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { INCREMENT, DECREMENT } from "./action-types";

/**
* 定义一个reducer函数
* 根据老的state和指定action, 处理返回一个新的state
* @param {*} state
* @param {Object} action
*/
export const counter = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
// 返回一个新的状态,不能修改原来的状态
return state + action.number;
case DECREMENT:
return state - action.number;
default:
return state;
}
};

components/counter.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
UI组件: 不包含任何redux API
a.只负责 UI 的呈现,不带有任何业务逻辑
b.通过props接收数据(一般数据和函数)
c.不使用任何 Redux 的 API
*/
import React from 'react'
import PropTypes from 'prop-types'

export default class Counter extends React.Component {

//声明store管理的状态和action函数,此处接收的内容要和容器组件App中connect()中定义的状态属性名和action函数名一致。
static propTypes = {
count: PropTypes.number.isRequired,
increment: PropTypes.func.isRequired,
decrement: PropTypes.func.isRequired,
incrementAsync: PropTypes.func.isRequired
}

render() {
return (
<div>
<h1>
{this.props.count}
</h1>
<p>
<button onClick={() => this.props.increment(1)}>increment</button>
<button onClick={() => this.props.decrement(1)}>decrement</button>
<button onClick={() => this.props.incrementAsync(1)}>incrementAsync</button>
</p>
</div>
)
}
}

containters/App.jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
包含Counter组件的容器组件
a.负责管理数据和业务逻辑,不负责UI的呈现
b.使用 Redux 的 API
*/
// 引入连接函数
import { connect } from 'react-redux'
import * as actions from "../redux/actions";
import Counter from '../components/counter'

/**
connect():用于包装UI组件从而生成容器组件
由于store是绑定在<Provider/>中的,而不是<Counter/>中,要在Counter组件中接收store里的内容,则需要让store和Counter组件进行关联,
connect()函数就起到了关联的作用。原理就是将Provider中store里的内容解析放到Counter组件中去。
*/
export default connect(
state => ({ count: state }),
{ ...actions }
)(Counter)
/*
connect(
    mapStateToprops, //即state对象的属性组成的对象
    mapDispatchToProps //action的相关函数组成的对象
  )(Counter)
*/

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React from "react";
import ReactDOM from "react-dom";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { counter } from "./redux/reducers";
import { Provider } from "react-redux";
import App from "./containters/App";

//根据一个reducer创建store对象
const store = createStore(
counter,
applyMiddleware(thunk), // 应用上异步中间件
);

/**
* Provider:让所有组件都可以得到state数据
*/
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root"),
);


----------- 本文结束 -----------




如果你觉得我的文章对你有帮助,你可以打赏我哦~
0%