ReactJS - Using Flux

ReactJS - 使用 Flux

要将 ReduxReact 结合起来使用,就还需要一些额外的库,其中最重要的是 react-redux

react-redux 提供了两个重要的对象,Providerconnect,前者使 React 组件可被连接(connectable),后者把 React 组件和 Redux 的 store 真正连接起来

本章节将介绍如何实现 Flux模式。 我们使用 Redux 类库,然后一步一步的把 ReduxReact 组合在一起

第一步 - 安装 Redux

安装 Redux 的命令如下

npm install --save react-redux

第二步 - 生成项目目录和文件

创建目录结构和相应的文件
React Redux Folder Structure

Step 3 - Actions

Action 是纯声明式的数据结构,只提供事件的所有要素,不提供逻辑。

actions/actions.js

export const ADD_TODO = 'ADD_TODO'
let nextTodoId = 0;
export function addTodo(text) {
return {
type: ADD_TODO,
id: nextTodoId++,
text
};
}

第四步 - Reducers

reducer 是一个匹配函数,action的发送是全局的:所有的reducer都可以捕捉到并匹配与自己相关与否,相关就拿走action中的要素进行逻辑处理,修改store中的状态,不相关就不对state做处理原样返回

reducers 作为事件处理函数,它接收 stateaction 作为参数,进行一系列的计算,然后返回计算后的 state

在本实例中,我们定义了两个函数,todo 用来添加待办事项, todos 用来生成列表。

帮助函数 combineReducers 方便管理和添加 reducers .

reducers/reducers.js

import { combineReducers } from 'redux'
import { ADD_TODO } from '../actions/actions'
function todo(state, action) {
switch (action.type) {
case ADD_TODO:
return {
id: action.id,
text: action.text,
}
default:
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
todo(undefined, action)
]
default:
return state
}
}
const todoApp = combineReducers({
todos
})
export default todoApp

Step 5 - Store

Redux 的 store 用来管理 React 应用的所有状态(state)
可以简单的使用 createStore 创建一个 store ,然后把它赋值给 providerstore属性就可以完成 storeprovider的绑定

main.js

import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './App.jsx'
import todoApp from './reducers/reducers'
let store = createStore(todoApp)
let rootElement = document.getElementById('app')
render(
<Provider store = {store}>
<App />
</Provider>,
rootElement
)

第六步 6 - App Component

App 组件是应用程序的入口组件,只有 App 组件能被 redux 唤醒。
其中 connect 函数是最重要的部分,他把 App 组件连接到 Redux 的 store

connect 使用 select 作为参数,而 select 函数从 Redux 的 store 中提取 state 数据,然后注入 props ( visibleTodos ) 到我们的组件中.

App.js

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { addTodo } from './actions/actions'
import AddTodo from './components/AddTodo.jsx'
import TodoList from './components/TodoList.jsx'
class App extends Component {
render() {
const { dispatch, visibleTodos } = this.props
return (
<div>
<AddTodo
onAddClick = {text ⇒
dispatch(addTodo(text))}
/>
<TodoList todos = {visibleTodos}/>
</div>
)
}
}
function select(state) {
return {
visibleTodos: state.todos
}
}
export default connect(select)(App)

Step 7 - Other Components

下面这些组件不会被 Redux 唤醒
也就是说,下面这些组件和 redux 可以说没有任何关系。

components/AddTodo.js

import React, { Component, PropTypes } from 'react'
export default class AddTodo extends Component {
render() {
return (
<div>
<input type = 'text' ref = 'input' />
<button onClick = {(e)this.handleClick(e)}>
Add
</button>
</div>
)
}
handleClick(e) {
const node = this.refs.input
const text = node.value.trim()
this.props.onAddClick(text)
node.value = ''
}
}

components/Todo.js

import React, { Component, PropTypes } from 'react'
export default class Todo extends Component {
render() {
return (
<li>
{this.props.text}
</li>
)
}
}

components/TodoList.js

import React, { Component, PropTypes } from 'react'
import Todo from './Todo.jsx'
export default class TodoList extends Component {
render() {
return (
<ul>
{this.props.todos.map(todo ⇒
<Todo
key = {todo.id}
{...todo}
/>
)}
</ul>
)
}
}

运行我们的 App,添加一个 待办事项 试一试吧
React Redux Example