redux + react

明智的做法是只在最顶层组件(如路由操作)里使用 Redux。其余内部组件仅仅是展示性的,所有数据都通过 props 传入。

redux + react_第1张图片
Paste_Image.png

示例: Todo 列表

入口文件

index.js

import React from 'react'
import { render } from 'react-dom'
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')
render(
  
    
  ,
  rootElement
)

Action 创建函数和常量

actions.js


/*
 * action 类型
 */

export const ADD_TODO = 'ADD_TODO';
export const COMPLETE_TODO = 'COMPLETE_TODO';
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'

/*
 * 其它的常量
 */

export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
};

/*
 * action 创建函数
 */

export function addTodo(text) {
  return { type: ADD_TODO, text }
}

export function completeTodo(index) {
  return { type: COMPLETE_TODO, index }
}

export function setVisibilityFilter(filter) {
  return { type: SET_VISIBILITY_FILTER, filter }
}

Reducers

reducers.js

import { combineReducers } from 'redux'
import { ADD_TODO, COMPLETE_TODO, SET_VISIBILITY_FILTER, VisibilityFilters } from './actions'
const { SHOW_ALL } = VisibilityFilters

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case COMPLETE_TODO:
      return [
        ...state.slice(0, action.index),
        Object.assign({}, state[action.index], {
          completed: true
        }),
        ...state.slice(action.index + 1)
      ]
    default:
      return state
  }
}

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp

容器组件

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 (
      
dispatch(addTodo(text)) } /> dispatch(completeTodo(index)) } />
dispatch(setVisibilityFilter(nextFilter)) } />
) } } App.propTypes = { visibleTodos: PropTypes.arrayOf(PropTypes.shape({ text: PropTypes.string.isRequired, completed: PropTypes.bool.isRequired }).isRequired).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 } } // 包装 component ,注入 dispatch 和 state 到其默认的 connect(select)(App) 中; export default connect(select)(App)

展示组件

components/AddTodo.js

import React, { Component, PropTypes } from 'react'

export default class AddTodo extends Component {
  render() {
    return (
      
) } handleClick(e) { const node = this.refs.input const text = node.value.trim() this.props.onAddClick(text) node.value = '' } } AddTodo.propTypes = { onAddClick: PropTypes.func.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 (
       {
        e.preventDefault()
        this.props.onFilterChange(filter)
      }}>
        {name}
      
    )
  }

  render() {
    return (
      

Show: {' '} {this.renderFilter('SHOW_ALL', 'All')} {', '} {this.renderFilter('SHOW_COMPLETED', 'Completed')} {', '} {this.renderFilter('SHOW_ACTIVE', 'Active')} .

) } } Footer.propTypes = { onFilterChange: PropTypes.func.isRequired, filter: PropTypes.oneOf([ 'SHOW_ALL', 'SHOW_COMPLETED', 'SHOW_ACTIVE' ]).isRequired }

components/Todo.js

import React, { Component, PropTypes } from 'react'

export default class Todo extends Component {
  render() {
    return (
      
  • {this.props.text}
  • ) } } 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 (
          
      {this.props.todos.map((todo, index) => this.props.onTodoClick(index)} /> )}
    ) } } TodoList.propTypes = { onTodoClick: PropTypes.func.isRequired, todos: PropTypes.arrayOf(PropTypes.shape({ text: PropTypes.string.isRequired, completed: PropTypes.bool.isRequired }).isRequired).isRequired }

    你可能感兴趣的:(redux + react)