📜  React Redux示例

📅  最后修改于: 2020-12-20 02:47:58             🧑  作者: Mango

React Redux示例

在本节中,我们将学习如何在React应用程序中实现Redux。在这里,我们提供了一个简单的示例来连接Redux和React。

步骤1使用create-react-app命令创建一个新的react项目。我选择项目名称:“ reactproject” 。现在,安装ReduxReact-Redux

javatpoint@root:~/Desktop$ npx create-react-app reactproject
javatpoint@root:~/Desktop/reactproject$ npm install redux react-redux --save

步骤2创建文件和文件夹

在此步骤中,我们需要为操作,reduce,组件和容器创建文件夹和文件。创建文件夹和文件后,我们的项目如下图所示。

步骤3的动作

它使用' type '属性来通知应发送到商店的数据。在此文件夹中,我们将创建两个文件: index.jsindex.spec.js 。在这里,我们创建了一个动作创建器,该动作创建器返回我们的动作并为每个创建的项目设置一个ID。

Index.js

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

export const setVisibilityFilter = filter => ({
  type: 'SET_VISIBILITY_FILTER',
  filter
})

export const toggleTodo = id => ({
  type: 'TOGGLE_TODO',
  id
})

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

Index.spec.js

import * as actions from './index'

describe('todo actions', () => {
  it('addTodo should create ADD_TODO action', () => {
    expect(actions.addTodo('Use Redux')).toEqual({
      type: 'ADD_TODO',
      id: 0,
      text: 'Use Redux'
    })
  })

  it('setVisibilityFilter should create SET_VISIBILITY_FILTER action', () => {
    expect(actions.setVisibilityFilter('active')).toEqual({
      type: 'SET_VISIBILITY_FILTER',
      filter: 'active'
    })
  })

  it('toggleTodo should create TOGGLE_TODO action', () => {
    expect(actions.toggleTodo(1)).toEqual({
      type: 'TOGGLE_TODO',
      id: 1
    })
  })
})

步骤4减速器

众所周知,Action仅会触发应用程序中的更改,而Reducers会指定这些更改。 Reducer是一个函数,它使用两个参数“ Action”和“ State”来计算并返回更新后的State。它从“操作”中读取有效负载,然后通过状态相应地更新“存储”。

在给定的文件中,每个Reducer管理自己的全局状态部分。每个Reducer的状态参数都不相同,并且对应于它管理的“状态”部分。当应用程序变大时,我们可以将Reducer拆分为单独的文件,并使它们完全独立并管理不同的数据域。

在这里,我们使用'combineReducers'帮助函数添加将来可能使用的任何新的Reducer。

index.js

import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'

export default combineReducers({
  todos,
  visibilityFilter
})

Todos.js

const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: false
        }
      ]
    case 'TOGGLE_TODO':
      return state.map(todo =>
        (todo.id === action.id)
          ? {...todo, completed: !todo.completed}
          : todo
      )
    default:
      return state
  }
}
export default todos

Todos.spec.js

import todos from './todos'

describe('todos reducer', () => {
  it('should handle initial state', () => {
    expect(
      todos(undefined, {})
    ).toEqual([])
  })

  it('should handle ADD_TODO', () => {
    expect(
      todos([], {
        type: 'ADD_TODO',
        text: 'Run the tests',
        id: 0
      })
    ).toEqual([
      {
        text: 'Run the tests',
        completed: false,
        id: 0
      }
    ])

    expect(
      todos([
        {
          text: 'Run the tests',
          completed: false,
          id: 0
        }
      ], {
        type: 'ADD_TODO',
        text: 'Use Redux',
        id: 1
      })
    ).toEqual([
      {
        text: 'Run the tests',
        completed: false,
        id: 0
      }, {
        text: 'Use Redux',
        completed: false,
        id: 1
      }
    ])

    expect(
      todos([
        {
          text: 'Run the tests',
          completed: false,
          id: 0
        }, {
          text: 'Use Redux',
          completed: false,
          id: 1
        }
      ], {
        type: 'ADD_TODO',
        text: 'Fix the tests',
        id: 2
      })
    ).toEqual([
      {
        text: 'Run the tests',
        completed: false,
        id: 0
      }, {
        text: 'Use Redux',
        completed: false,
        id: 1
      }, {
        text: 'Fix the tests',
        completed: false,
        id: 2
      }
    ])
  })

  it('should handle TOGGLE_TODO', () => {
    expect(
      todos([
        {
          text: 'Run the tests',
          completed: false,
          id: 1
        }, {
          text: 'Use Redux',
          completed: false,
          id: 0
        }
      ], {
        type: 'TOGGLE_TODO',
        id: 1
      })
    ).toEqual([
      {
        text: 'Run the tests',
        completed: true,
        id: 1
      }, {
        text: 'Use Redux',
        completed: false,
        id: 0
      }
    ])
  })
})

VisibilityFilter.js

import { VisibilityFilters } from '../actions'

const visibilityFilter = (state = VisibilityFilters.SHOW_ALL, action) => {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}
export default visibilityFilter

步骤5组件

它是一个表示组件,它与事物的外观(例如标记,样式)有关。它接收数据并仅通过prop调用回调。它不知道数据来自何处或如何更改。它仅呈现给他们的东西。

App.js

它是在UI中呈现所有内容的根组件。

import React from 'react'
import Footer from './Footer'
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'

const App = () => (
  
) export default App

Footer.js

它告诉用户当前在何处更改了可见的待办事项

import React from 'react'
import FilterLink from '../containers/FilterLink'
import { VisibilityFilters } from '../actions'

const Footer = () => (
  

Show: All {', '} Active {', '} Completed

) export default Footer

Link.js

这是带有回调的链接。

import React from 'react'
import PropTypes from 'prop-types'

const Link = ({ active, children, onClick }) => {
  if (active) {
    return {children}
  }

  return (
     {
        e.preventDefault()
        onClick()
      }}
    >
      {children}
    
  )
}

Link.propTypes = {
  active: PropTypes.bool.isRequired,
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func.isRequired
}

export default Link

Todo.js

它表示显示文本的单个待办事项。

import React from 'react'
import PropTypes from 'prop-types'

const Todo = ({ onClick, completed, text }) => (
  
  • {text}
  • ) Todo.propTypes = { onClick: PropTypes.func.isRequired, completed: PropTypes.bool.isRequired, text: PropTypes.string.isRequired } export default Todo

    TodoList.js

    它是显示可见待办事项{ID,文本,已完成}的列表。

    import React from 'react'
    import PropTypes from 'prop-types'
    import Todo from './Todo'
    
    const TodoList = ({ todos, onTodoClick }) => (
      
      {todos.map((todo, index) => ( onTodoClick(index)} /> ))}
    ) TodoList.propTypes = { todos: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.number.isRequired, completed: PropTypes.bool.isRequired, text: PropTypes.string.isRequired }).isRequired ).isRequired, onTodoClick: PropTypes.func.isRequired } export default TodoList

    步骤6的容器

    它是一个容器组件,与诸如数据提取,更新状态之类的工作方式有关。它为表示性组件或其他容器组件提供数据和行为。它使用Redux State读取数据并调度Redux Action来更新数据。

    AddTodo.js

    它包含带有ADD(提交)按钮的输入字段。

    import React from 'react'
    import { connect } from 'react-redux'
    import { addTodo } from '../actions'
    
    const AddTodo = ({ dispatch }) => {
      let input
    
      return (
        
    { e.preventDefault() if (!input.value.trim()) { return } dispatch(addTodo(input.value)) input.value = '' }}> input = node} />
    ) } export default connect()(AddTodo)

    FilterLink.js

    它代表当前的可见性过滤器并呈现一个链接。

    import { connect } from 'react-redux'
    import { setVisibilityFilter } from '../actions'
    import Link from '../components/Link'
    
    const mapStateToProps = (state, ownProps) => ({
      active: ownProps.filter === state.visibilityFilter
    })
    
    const mapDispatchToProps = (dispatch, ownProps) => ({
      onClick: () => dispatch(setVisibilityFilter(ownProps.filter))
    })
    
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(Link)
    

    VisibleTodoList.js

    它过滤待办事项并渲染TodoList。

    import { connect } from 'react-redux'
    import { toggleTodo } from '../actions'
    import TodoList from '../components/TodoList'
    import { VisibilityFilters } from '../actions'
    
    const getVisibleTodos = (todos, filter) => {
      switch (filter) {
        case VisibilityFilters.SHOW_ALL:
          return todos
        case VisibilityFilters.SHOW_COMPLETED:
          return todos.filter(t => t.completed)
        case VisibilityFilters.SHOW_ACTIVE:
          return todos.filter(t => !t.completed)
        default:
          throw new Error('Unknown filter: ' + filter)
      }
    }
    
    const mapStateToProps = state => ({
      todos: getVisibleTodos(state.todos, state.visibilityFilter)
    })
    
    const mapDispatchToProps = dispatch => ({
      toggleTodo: id => dispatch(toggleTodo(id))
    })
    
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(TodoList)
    

    步骤7商店

    所有容器组件都需要访问Redux Store才能订阅。为此,我们需要将它(存储)作为道具传递给每个容器组件。但是,它变得乏味。所以我们建议使用特殊的React Redux组件这使商店可用于所有容器组件,而无需显式传递它。渲染根组件时只使用一次。

    index.js

    import React from 'react'
    import { render } from 'react-dom'
    import { createStore } from 'redux'
    import { Provider } from 'react-redux'
    import App from './components/App'
    import rootReducer from './reducers'
    
    const store = createStore(rootReducer)
    
    render(
      
        
      ,
      document.getElementById('root')
    )
    

    输出量

    当我们执行该应用程序时,其输出如下屏幕所示。

    现在,我们将能够在列表中添加项目。

    可在此处显示React-Redux示例的详细说明: https ://redux.js.org/basics/usage-with-react。