Redux 是 React 的一个独立实体,可以与任何 JavaScript 前端框架或文本 JavaScript 一起使用,然而,React 和 Redux 很常被一起使用,因此 React Redux库提供了简单的连接,使两者非常容易连接。
React Redux 连接的 API 非常简单:提供商组件使我们的商店在我们的应用程序中可访问,连接功能创建容器组件,可以读取商店的状态并发送操作。
开始的
让我们初始化一个 React 项目,并确保我们有必要的依赖性. 让我们使用 Create React App创建一个样本标记管理应用程序:
1$ npx create-react-app fancy-bookmarks
在这里,请注意使用 npx来确保我们正在使用 Create React App 的最新版本。
现在让我们将cd
插入我们的应用程序目录,并添加减少和反应减少包:
1$ yarn add redux react-redux
2
3# or, using npm:
4$ npm install redux react-redux
减少设置
现在让我们为我们的应用程序做Redux设置,我不会在这里解释很多,因为,但如果您对Redux一般来说是新手,请看看我们的 介绍Redux。
首先,一些行动类型:
1[label actions/types.js]
2export const ADD_BOOKMARK = 'ADD_BOOKMARK';
3export const DELETE_BOOKMARK = 'DELETE_BOOKMARK';
一些动作创造者与我们的动作类型相结合:
1[label actions/index.js]
2import uuidv4 from 'uuid/v4';
3import { ADD_BOOKMARK, DELETE_BOOKMARK } from './types';
4
5export const addBookmark = ({ title, url }) => ({
6 type: ADD_BOOKMARK,
7 payload: {
8 id: uuidv4(),
9 title,
10 url
11 }
12});
13
14export const deleteBookmark = id => ({
15 type: DELETE_BOOKMARK,
16 payload: {
17 id
18 }
19});
<$>[注] 在这里,你会注意到我也在使用 uuid 库来生成随机 ID。
这里是我们为我们的简单应用程序所需的唯一减速器:
1[label reducer/index.js]
2import { ADD_BOOKMARK, DELETE_BOOKMARK } from '../actions/types';
3
4export default function bookmarksReducer(state = [], action) {
5 switch (action.type) {
6 case ADD_BOOKMARK:
7 return [...state, action.payload];
8 case DELETE_BOOKMARK:
9 return state.filter(bookmark => bookmark.id !== action.payload.id);
10 default:
11 return state;
12 }
13}
正如你所看到的,到目前为止,我们完全在Redux地带,还没有做任何事情,让我们的React应用程序无缝地与我们的Redux商店交谈。
供应商组件
我们将使用 React Redux 提供商组件来包装我们的主要应用组件,并从任何容器组件(连接组件)下到 React 组件树下访问应用程序的 Redux 商店:
1[label index.js]
2import React from 'react';
3import ReactDOM from 'react-dom';
4import { createStore } from 'redux';
5import { Provider } from 'react-redux';
6import rootReducer from './reducers';
7
8import App from './App';
9
10const store = createStore(rootReducer);
11
12ReactDOM.render(
13 <Provider store={store}>
14 <App />
15 </Provider>,
16 document.getElementById('root')
17);
如果你正在使用 React Router,你会围绕 BrowserRouter 组件包装 Provider 组件。
集装箱组件和连接功能
现在 Redux 商店在我们的应用程序中可以访问,我们仍然需要创建一些容器组件,也称为连接组件,这些组件将能够从商店读取或发送操作。
1[label App.js]
2import React, { Component } from 'react';
3import AddBookmark from './containers/AddBookmark';
4import BookmarksList from './containers/BookmarksList';
5
6class App extends Component {
7 render() {
8 return (
9 <div>
10 <AddBookmark />
11 <BookmarksList />
12 </div>
13 );
14 }
15}
16
17export default App;
现在对于我们的第一个容器组件,BookmarksList组件:
1[label containers/BookmarksList.js]
2import React from 'react';
3import { connect } from 'react-redux';
4import Bookmark from '../components/Bookmark';
5import { deleteBookmark } from '../actions';
6
7function BookmarksList({ bookmarks, onDelete }) {
8 return (
9 <div>
10 {bookmarks.map(bookmark => {
11 return (
12 <Bookmark bookmark={bookmark} onDelete={onDelete} key={bookmark.id} />
13 );
14 })}
15 </div>
16 );
17}
18
19const mapStateToProps = state => {
20 return {
21 bookmarks: state
22 };
23};
24
25const mapDispatchToProps = dispatch => {
26 return {
27 onDelete: id => {
28 dispatch(deleteBookmark(id));
29 }
30 };
31};
32
33export default connect(
34 mapStateToProps,
35 mapDispatchToProps
36)(BookmarksList);
我们使用React Redux的连接函数,并通过一个mapStateToProps
函数和一个mapDispatchToProps
函数。
「mapStateToProps」接收状态的当前值,应该返回一个使状态的片段作为连接组件的附加值的对象。
1const mapStateToProps = state => {
2 return {
3 users: state.users,
4 todos: state.todos,
5 // ...
6 };
7};
「mapStateToProps」接收商店的发送方法,并应该返回一个对象,使一些回复可用作为补贴,然后将所需的操作发送到商店。
接下来是 AddBookmark 组件:
1[label containers/AddBookmark.js]
2import { connect } from 'react-redux';
3import { addBookmark } from '../actions';
4import NewBookmark from '../components/NewBookmark';
5
6const mapDispatchToProps = dispatch => {
7 return {
8 onAddBookmark: bookmark => {
9 dispatch(addBookmark(bookmark));
10 }
11 };
12};
13
14export default connect(
15 null,
16 mapDispatchToProps
17)(NewBookmark);
此组件不需要从商店中读取,所以我们将 null 作为连接函数的第一个参数。
您还会注意到,这个第二个容器组件组件不会自行渲染任何内容,而整个用户界面渲染部分则留给了 NewBookmark 演示组件。
介绍组件
演示组件更简单,没有直接进入商店。相反,他们从容器组件中收到来自状态的值或呼叫我们的动作创作者的回报。他们不需要知道任何关于Redux的信息,而只是给他们的专利的功能。
例如,这里是我们的 Bookmark 演示组件,该组件使一个 bookmark:
1[label components/Bookmark.js]
2import React from 'react';
3
4const styles = {
5 borderBottom: '2px solid #eee',
6 background: '#fafafa',
7 margin: '.75rem auto',
8 padding: '.6rem 1rem',
9 maxWidth: '500px',
10 borderRadius: '7px'
11};
12
13export default ({ bookmark: { title, url, id }, onDelete }) => {
14 return (
15 <div style={styles}>
16 <h2>{title}</h2>
17 <p>URL: {url}</p>
18 <button type="button" onClick={() => onDelete(id)}>
19 Remove
20 </button>
21 </div>
22 );
23};
正如你所看到的,它会收到标记以及在删除回调作为奖励。
在NewBookmark的情况下,它不是一个纯粹的演示组件,而是更像是混合组件,因为它对输入值保持了一些本地状态。
1[label components/NewBookmark.js]
2import React from 'react';
3
4class NewBookmark extends React.Component {
5 state = {
6 title: '',
7 url: ''
8 };
9
10 handleInputChange = e => {
11 this.setState({
12 [e.target.name]: e.target.value
13 });
14 };
15
16 handleSubmit = e => {
17 e.preventDefault();
18 if (this.state.title.trim() && this.state.url.trim()) {
19 this.props.onAddBookmark(this.state);
20 this.handleReset();
21 }
22 };
23
24 handleReset = () => {
25 this.setState({
26 title: '',
27 url: ''
28 });
29 };
30
31 render() {
32 return (
33 <form onSubmit={this.handleSubmit}>
34 <input
35 type="text"
36 placeholder="title"
37 name="title"
38 onChange={this.handleInputChange}
39 value={this.state.title}
40 />
41 <input
42 type="text"
43 placeholder="URL"
44 name="url"
45 onChange={this.handleInputChange}
46 value={this.state.url}
47 />
48 <hr />
49 <button type="submit">Add bookmark</button>
50 <button type="button" onClick={this.handleReset}>
51 Reset
52 </button>
53 </form>
54 );
55 }
56}
57
58export default NewBookmark;
我们的简单的标记管理应用程序正在工作,从商店获取数据并发送操作。
有了這一點,你應該離開比賽! 對於這個主題的不同看法,你也可以看看 官方文件 。