<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 搭配 React 這里需要再強調一下:Redux 和 React 之間沒有關系。Redux 支持 React、Angular、Ember、jQuery 甚至純 JavaScript。 盡管如此,Redux 還是和 [React](http://facebook.github.io/react/) 和 [Deku](https://github.com/dekujs/deku) 這類框架搭配起來用最好,因為這類框架允許你以 state 函數的形式來描述界面,Redux 通過 action 的形式來發起 state 變化。 下面使用 React 來開發一個 todo 任務管理應用。 ### 安裝 React Redux Redux 默認并不包含 [React 綁定庫](https://github.com/gaearon/react-redux),需要單獨安裝。 ~~~ npm install --save react-redux ~~~ ### 智能組件(Smart Components)和笨拙組件(Dumb Components) Redux 的 React 綁定庫擁抱了 [“智能”組件和“笨拙”組件相分離](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) 的開發思想。 明智的做法是只在最頂層組件(如路由操作)里使用 Redux。內部組件應該像木偶一樣保持“呆滯”,所有數據都通過 props 傳入。 | | 位置 | 使用 Redux | 讀取數據 | 修改數據 | |-----|-----|-----|-----|-----| | “智能”組件 | 最頂層,路由處理 | 是 | 從 Redux 獲取 state | 向 Redux 發起 actions | | “笨拙”組件 | 中間和子組件 | 否 | 從 props 獲取數據 | 從 props 調用回調函數 | 在這個 todo 應用中,只應有一個“智能”組件,它存在于組件的最頂層。在復雜的應用中,也有可能會有多個智能組件。雖然你也可以嵌套使用“智能”組件,但應該盡可能的使用傳遞 props 的形式。 ### 設計組件層次結構 還記得當初如何 [設計 reducer 結構](#) 嗎?現在就要定義與它匹配的界面的層次結構。其實這不是 Redux 相關的工作,[React 開發思想](https://facebook.github.io/react/docs/thinking-in-react.html)在這方面解釋的非常棒。 我們的概要設計很簡單。我們想要顯示一個 todo 項的列表。一個 todo 項被點擊后,會增加一條刪除線并標記 completed。我們會顯示用戶新增一個 todo 字段。在 footer 里顯示一個可切換的顯示全部/只顯示 completed 的/只顯示 incompleted 的 todos。 以下的這些組件(和它們的 props )就是從這個設計里來的: - **`AddTodo`** 輸入字段的輸入框和按鈕。 - `onAddClick(text: string)` 當按鈕被點擊時調用的回調函數。 - **`TodoList`** 用于顯示 todos 列表。 - `todos: Array` 以 `{ text, completed }` 形式顯示的 todo 項數組。 - `onTodoClick(index: number)` 當 todo 項被點擊時調用的回調函數。 - **`Todo`** 一個 todo 項。 - `text: string` 顯示的文本內容。 - `completed: boolean` todo 項是否顯示刪除線。 - `onClick()` 當 todo 項被點擊時調用的回調函數。 - **`Footer`** 一個允許用戶改變可見 todo 過濾器的組件。 - `filter: string` 當前的過濾器為: `'SHOW_ALL'`、 `'SHOW_COMPLETED'` 或 `'SHOW_ACTIVE'`。 - `onFilterChange(nextFilter: string)`: 當用戶選擇不同的過濾器時調用的回調函數。 這些全部都是“笨拙”的組件。它們不知道數據是**從**哪里來的,或者數據是**怎么**變化的。你傳入什么,它們就渲染什么。 如果你要把 Redux 遷移到別的上,你應該要保持這些組件的一致性。因為它們不依賴 Redux。 直接寫就是了!我們已經不用綁定到 Redux。你可以在開發過程中給出一些實驗數據,直到它們渲染對了。 ### 笨拙組件 這就是普通的 React 組件,所以就不在詳述。直接看代碼: #### `components/AddTodo.js` ~~~ import React, { findDOMNode, 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 = findDOMNode(this.refs.input); const text = node.value.trim(); this.props.onAddClick(text); node.value = ''; } } AddTodo.propTypes = { onAddClick: PropTypes.func.isRequired }; ~~~ #### `components/Todo.js` ~~~ import React, { Component, PropTypes } from 'react'; export default class Todo extends Component { render() { return ( <li onClick={this.props.onClick} style={{ textDecoration: this.props.completed ? 'line-through' : 'none', cursor: this.props.completed ? 'default' : 'pointer' }}> {this.props.text} </li> ); } } Todo.propTypes = { onClick: PropTypes.func.isRequired, text: PropTypes.string.isRequired, completed: PropTypes.bool.isRequired }; ~~~ #### `components/TodoList.js` ~~~ import React, { Component, PropTypes } from 'react'; import Todo from './Todo'; export default class TodoList extends Component { render() { return ( <ul> {this.props.todos.map((todo, index) => <Todo {...todo} key={index} onClick={() => this.props.onTodoClick(index)} /> )} </ul> ); } } TodoList.propTypes = { onTodoClick: PropTypes.func.isRequired, todos: PropTypes.arrayOf(PropTypes.shape({ text: PropTypes.string.isRequired, completed: PropTypes.bool.isRequired }).isRequired).isRequired }; ~~~ #### `components/Footer.js` ~~~ import React, { Component, PropTypes } from 'react'; export default class Footer extends Component { renderFilter(filter, name) { if (filter === this.props.filter) { return name; } return ( <a href='#' onClick={e => { e.preventDefault(); this.props.onFilterChange(filter); }}> {name} </a> ); } render() { return ( <p> Show: {' '} {this.renderFilter('SHOW_ALL', 'All')} {', '} {this.renderFilter('SHOW_COMPLETED', 'Completed')} {', '} {this.renderFilter('SHOW_ACTIVE', 'Active')} . </p> ); } } Footer.propTypes = { onFilterChange: PropTypes.func.isRequired, filter: PropTypes.oneOf([ 'SHOW_ALL', 'SHOW_COMPLETED', 'SHOW_ACTIVE' ]).isRequired }; ~~~ 就這些,現在開發一個笨拙型的組件 `App` 把它們渲染出來,驗證下是否工作。 #### `containers/App.js` ~~~ import React, { Component } from 'react'; import AddTodo from '../components/AddTodo'; import TodoList from '../components/TodoList'; import Footer from '../components/Footer'; export default class App extends Component { render() { return ( <div> <AddTodo onAddClick={text => console.log('add todo', text) } /> <TodoList todos={[{ text: 'Use Redux', completed: true }, { text: 'Learn to connect it to React', completed: false }]} onTodoClick={todo => console.log('todo clicked', todo) } /> <Footer filter='SHOW_ALL' onFilterChange={filter => console.log('filter change', filter) } /> </div> ); } } ~~~ 渲染 `<App />` 結果如下: ![](https://box.kancloud.cn/2015-11-19_564dae5bdb912.png) 單獨來看,并沒有什么特別,現在把它和 Redux 連起來。 ### 連接到 Redux 我們需要做出兩個變化,將 `App` 組件連接到 Redux 并且讓它能夠 dispatch actions 以及從 Redux store 讀取到 state。 首先,我們需要獲取從之前安裝好的 [`react-redux`](http://github.com/gaearon/react-redux) 提供的 `Provider`,并且在渲染之前**將根組件包裝進 `<Provider>`**。 #### `index.js` ~~~ import React from 'react'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import App from './containers/App'; import todoApp from './reducers'; let store = createStore(todoApp); let rootElement = document.getElementById('root'); React.render( // 為了解決在 React 0.13 的一個問題 // 子標簽必須包裝成一個 function。 <Provider store={store}> {() => <App />} </Provider>, rootElement ); ~~~ 這使得我們的 store 能為下面的組件所用。(在內部,這個是通過 React 的 ["context" 特性](http://facebook.github.io/react/docs/context.html)實現。) 接著,我們**想要通過 [`react-redux`](http://github.com/gaearon/react-redux) 提供的 `connect()` 方法將包裝好的組件連接到Redux**。盡量只做一個頂層的組件,或者 route 處理。從技術上來說你可以將應用中的任何一個組件 `connect()` 到 Redux store 中,但盡量要避免這么做,因為這個數據流很難追蹤。 **任何一個從 `connect()` 包裝好的組件都可以得到一個 [`dispatch`](#) 方法作為組件的 props。**`connect()` 的唯一參數是 **selector**。此方法可以從 Redux store 接收到全局的 state,然后返回一個你的組件中需要的 props。最簡單的情況下,可以返回一個初始的 `state` ,但你可能希望它發生了變化。 為了組合 selectors 更有效率,不妨看看 [reselect](https://github.com/faassen/reselect)。在這個例子中我們不會用到它,但它適合更大的應用。 #### `containers/App.js` ~~~ import React, { Component, PropTypes } from 'react'; import { connect } from 'react-redux'; import { addTodo, completeTodo, setVisibilityFilter, VisibilityFilters } from '../actions'; import AddTodo from '../components/AddTodo'; import TodoList from '../components/TodoList'; import Footer from '../components/Footer'; class App extends Component { render() { // Injected by connect() call: const { dispatch, visibleTodos, visibilityFilter } = this.props; return ( <div> <AddTodo onAddClick={text => dispatch(addTodo(text)) } /> <TodoList todos={this.props.visibleTodos} onTodoClick={index => dispatch(completeTodo(index)) } /> <Footer filter={visibilityFilter} onFilterChange={nextFilter => dispatch(setVisibilityFilter(nextFilter)) } /> </div> ); } } App.propTypes = { visibleTodos: PropTypes.arrayOf(PropTypes.shape({ text: PropTypes.string.isRequired, completed: PropTypes.bool.isRequired })), visibilityFilter: PropTypes.oneOf([ 'SHOW_ALL', 'SHOW_COMPLETED', 'SHOW_ACTIVE' ]).isRequired }; function selectTodos(todos, filter) { switch (filter) { case VisibilityFilters.SHOW_ALL: return todos; case VisibilityFilters.SHOW_COMPLETED: return todos.filter(todo => todo.completed); case VisibilityFilters.SHOW_ACTIVE: return todos.filter(todo => !todo.completed); } } // Which props do we want to inject, given the global state? // Note: use https://github.com/faassen/reselect for better performance. function select(state) { return { visibleTodos: selectTodos(state.todos, state.visibilityFilter), visibilityFilter: state.visibilityFilter }; } // Wrap the component to inject dispatch and state into it export default connect(select)(App); ~~~ 到此為止,迷你型的任務管理應用就開發完畢。 ### 下一步 參照 [本示例完整](#) 來深化理解。然后就可以跳到 [高級教程](#) 學習網絡請求處理和路由。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看