How does Redux change UI in React?
I think the confusion you have is that part of reducer composition and selectors.
Let's look at it in a reverse order, from the UI back.
In the connected component containers/VisibleTodoList.js it gets the todos
from the "state" (the global store object of redux
) inside mapStateToProps
, while passing it through the getVisibleTodos
method.
Which can be called a selector, as it selects and returns only a portion of the data that it receives:
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
The state
(redux store) that passed to mapStateToProps
came from the root reducer reducers/index.js and is actually a single reducer (object) that represent the combination of all other reducers via the combineReducers
utility of redux
:
import { combineReducers } from 'redux' import todos from './todos' import visibilityFilter from './visibilityFilter' const todoApp = combineReducers({ todos, visibilityFilter }) export default todoApp
As you can see, the todos
reducer is there. so that's why inside the mapStateToProps
we call it like this state.todos
.
Here is the 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
On each action of type 'ADD_TODO'
it will return a new state with the new todo
:
case 'ADD_TODO': return [ ...state, { id: action.id, text: action.text, completed: false } ]
This the the action creator for it inside actions/index.js:
let nextTodoId = 0export const addTodo = text => { return { type: 'ADD_TODO', id: nextTodoId++, text }}
So here is the full flow of redux
(i omitted the button that calls the action as i assume this is obvious part for you).
Well, almost a full flow, none of this could have happened without the Provider
HOC that wraps the App
and inject the store to it in index.js:
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'))
Now when the redux
state
changes, a call to mapStateToProps
is invoked that will return the new mapped props
. connect
will pass those new props
and this will trigger a new render
call (actually the entire react life cycle flow) to the connected component.
This way the UI will be re-rendered with the fresh new data from the store.
connect is typically used to connect react component and Redux state.connect is a higher order component. The component which are using connect function are wrapped inside it. The method signature isconnect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])mapStateToProps has access to redux state and mapDispathToProps has access to store.dispatch. All the props are merged and passed as props to underlying component. Redux has only single state of truth. store that is passed as a props to Provider components has a method called store.getState().
So , keep one thing in mind react components are data driven . Data derives UI. React components rerender only when state is changed or props have been modified. you make change in any of two , components goes through various life cycle methods.