Redux如何在React中更改UI?

Wor*_*sor 6 javascript user-interface reactjs redux

我一直在努力围绕这个概念,但没有运气.官方的React教程非常好,但对我来说这太复杂了,只是有点太难了.

我正在尝试理解Redux,到目前为止,我可以创建动作,减少器,我可以调度一个动作,然后在调度后查看存储状态如何变化.我还设法了解connectreact-redux并且它运行良好,我能够从我的应用程序的任何地方触发调度.所以我想我差点搞清楚了.几乎,因为这是房间里的大象 - 我发送动作,我看到Redux状态发生变化,但我如何更改UI?

例如text,我的初始状态中的对象具有值,Initial text并且一旦单击按钮,我想将文本更改为Clicked text并在UI中的某处显示文本(让我们说按钮).

如何在React中"访问"Redux状态,如何动态更改它?

没有React似乎很简单,例如:https://jsfiddle.net/loktar/v1kvcjbu/ - render函数处理一切,我理解这里发生的一切.

但另一方面来自官方React + Redux教程的"todo"看起来像这样:https://redux.js.org/docs/basics/ExampleTodoList.html,它太复杂了我不知道在哪里看.

该Add Todo按钮提交一个调度dispatch(addTodo(input.value))操作的表单.动作本身不会增加ID并将文本传递给存储,而reducer只返回新状态.然后如何在页面上呈现待办事项?哪里?我此时迷路了.也许有更简单的教程,我喜欢有一个按钮Redux教程,它仍然可以复杂的多层组件:(

我怀疑魔法发生在TodoList.js中,因为他们正在那里映射,但我仍然不知道todos来自哪里,以及它与Redux有什么关系(该文件中没有简单的reducer/action/dispatch) .

谢谢你的帮助!

Sag*_*b.g 5

我认为你的混淆是减速器组成和选择器的一部分.

让我们从UI背面以相反的顺序查看它.

在连接组件 容器/ VisibleTodoList.js中,它todos从内部的"状态"(全局存储对象redux)获取mapStateToProps,同时将其传递给getVisibleTodos方法.
这可以称为选择器,因为它只选择并返回它接收的部分数据:

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    case 'SHOW_ALL':
    default:
      return todos
  }
}

const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onTodoClick: id => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList
Run Code Online (Sandbox Code Playgroud)

state传递给的(redux存储)mapStateToProps来自根reducer redurs/index.js,实际上是一个reducer(object),它通过以下combineReducers实用程序代表所有其他reducer的组合redux:

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

  const todoApp = combineReducers({
    todos,
    visibilityFilter
  })

  export default todoApp   
Run Code Online (Sandbox Code Playgroud)

如您所见,todos减速机就在那里.所以这就是mapStateToProps我们称之为内部的原因state.todos.

这是reducers/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  
Run Code Online (Sandbox Code Playgroud)

在每个类型的操作上'ADD_TODO',它将返回一个新的状态todo:

case 'ADD_TODO':
          return [
            ...state,
            {
              id: action.id,
              text: action.text,
              completed: false
            }
          ]  
Run Code Online (Sandbox Code Playgroud)

这是actions/index.js中的动作创建者:

let nextTodoId = 0
export const addTodo = text => {
  return {
    type: 'ADD_TODO',
    id: nextTodoId++,
    text
  }
}
Run Code Online (Sandbox Code Playgroud)

所以这里是完整的流程redux(我省略了调用动作的按钮,因为我认为这显然是你的一部分).
好吧,几乎是一个完整的流程,如果没有Provider包装App并在index.js中将商店注入商店的HOC,这一切都不可能发生:

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
Run Code Online (Sandbox Code Playgroud)

现在当redux state更改时,mapStateToProps调用一个将返回新映射的调用props.connect将传递那些新的props,这将触发一个新的render调用(实际上是整个反应生命周期流程)到连接的组件.
这样,UI将使用来自商店的新数据重新呈现.