[Redux] Passing the Store Down Explicitly via Props
n the previous lessons, we used this tool to up level variable to refer to the Redux chore. The components that access this chore, such as the container components, read this straight from it, subscribe to this chore, and dispatch actions on this chore using this chore top-level variable.
This approach works fine for JS bin example where everything is in a single file. However, it doesn't scale to real applications for several reasons.
First of all, it makes your container components harder to test because they reference a specific chore, but you might want to supply a different marks chore in the test. Secondly, it makes it very hard to implement universal replications that are rendered on the server, because on the server, you want to supply a different chore instance for every request because different requests have different data.
Every container component needs a reference to this chore so unfortunately, we have to pass it down to every component as a prop. It's less effort than passing different data through every component, but it's still inconvenient. So, don't worry, we'll find a better solution later, but for now, we need to see the problem.
const todo = (state, action) => { switch (action.type) { case 'ADD_TODO': return { id: action.id, text: action.text, completed: false }; case 'TOGGLE_TODO': if (state.id !== action.id) { return state; } return { ...state, completed: !state.completed }; default: return state; } }; const todos = (state = [], action) => { switch (action.type) { case 'ADD_TODO': return [ ...state, todo(undefined, action) ]; case 'TOGGLE_TODO': return state.map(t => todo(t, action) ); default: return state; } }; const visibilityFilter = ( state = 'SHOW_ALL', action ) => { switch (action.type) { case 'SET_VISIBILITY_FILTER': return action.filter; default: return state; } }; const { combineReducers } = Redux; const todoApp = combineReducers({ todos, visibilityFilter }); const { Component } = React; const Link = ({ active, children, onClick }) => { if (active) { return <span>{children}</span>; } return ( <a href='#' onClick={e => { e.preventDefault(); onClick(); }} > {children} </a> ); }; class FilterLink extends Component { componentDidMount() { const { store } = this.props; this.unsubscribe = store.subscribe(() => this.forceUpdate() ); } componentWillUnmount() { this.unsubscribe(); } render() { const props = this.props; const { store } = props; const state = store.getState(); return ( <Link active={ props.filter === state.visibilityFilter } onClick={() => store.dispatch({ type: 'SET_VISIBILITY_FILTER', filter: props.filter }) } > {props.children} </Link> ); } } const Footer = ({ store }) => ( <p> Show: {' '} <FilterLink filter='SHOW_ALL' store={store} > All </FilterLink> {', '} <FilterLink filter='SHOW_ACTIVE' store={store} > Active </FilterLink> {', '} <FilterLink filter='SHOW_COMPLETED' store={store} > Completed </FilterLink> </p> ); const Todo = ({ onClick, completed, text }) => ( <li onClick={onClick} style={{ textDecoration: completed ? 'line-through' : 'none' }} > {text} </li> ); const TodoList = ({ todos, onTodoClick }) => ( <ul> {todos.map(todo => <Todo key={todo.id} {...todo} onClick={() => onTodoClick(todo.id)} /> )} </ul> ); let nextTodoId = 0; const AddTodo = ({ store }) => { let input; return ( <div> <input ref={node => { input = node; }} /> <button onClick={() => { store.dispatch({ type: 'ADD_TODO', id: nextTodoId++, text: input.value }) input.value = ''; }}> Add Todo </button> </div> ); }; const getVisibleTodos = ( todos, filter ) => { switch (filter) { case 'SHOW_ALL': return todos; case 'SHOW_COMPLETED': return todos.filter( t => t.completed ); case 'SHOW_ACTIVE': return todos.filter( t => !t.completed ); } } class VisibleTodoList extends Component { componentDidMount() { const { store } = this.props; this.unsubscribe = store.subscribe(() => this.forceUpdate() ); } componentWillUnmount() { this.unsubscribe(); } render() { const props = this.props; const { store } = props; const state = store.getState(); return ( <TodoList todos={ getVisibleTodos( state.todos, state.visibilityFilter ) } onTodoClick={id => store.dispatch({ type: 'TOGGLE_TODO', id }) } /> ); } } const TodoApp = ({ store }) => ( <div> <AddTodo store={store} /> <VisibleTodoList store={store} /> <Footer store={store} /> </div> ); const { createStore } = Redux; ReactDOM.render( <TodoApp store={createStore(todoApp)} />, document.getElementById('root') );
相关文章
- 自考——The First Step
- java错误:The superclass "javax.servlet.http.HttpServlet" was not found on the Java Bu
- [翻译] The Amazing Audio Engine
- [Typescript] Identity function pattern - Using Identity function to enforce the type 01
- [Functional Programming ADT] Adapt Redux Actions/Reducers for Use with the State ADT
- [Redux] Normalizing the State Shape
- [Redux] Refactoring the Entry Point
- [Redux] Passing the Store Down with <Provider> from React Redux
- [React Testing] The Redux Store - Multiple Actions
- [PWA] 15. Using The IDB Cache And Display Entries
- [React Testing] The Redux Store - Multiple Actions
- 解决The type or namespace name 'XXXX' does not exist in the namespace 'XXXXXXXXX' 的错误
- Touch the AppCache manifest file
- 【Educational Codeforces Round 48 (Rated for Div. 2) C】 Vasya And The Mushrooms
- 成功解决h5py__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float
- 已解决The above exception was the direct cause of the following exception:
- 【K3s】第25篇 解决The connection to the server localhost:8080 was refused
- The practice program of C on point
- [TroubleShootin]The backup set holds a backup of a database other than the existing 'xxdb' database.
- 魔戒 (The Lord of the Rings,又译《指环王》)
- 解决办法:错误异常The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
- Your configuration specifies to merge with the ref
- 【2023年4月美赛加赛】Z题:The Future of the Olympics 思路、建模方案、数据来源、相关资料
- 【霍洛维兹数据结构】数组和结构 | ARRAYS AND STRUCTURES | THE SPARSE MATRIX 稀疏矩阵
- 解决办法:The name 'Response' does not exist in the current context