[Redux] Generating Containers with connect() from React Redux (AddTodo)
Code to be refacted:
- const AddTodo = (props, { 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>
- );
- };
- AddTodo.contextTypes = {
- store: React.PropTypes.object
- };
Instead of passing:
- const AddTodo = (props, { store }) => {
We can only pass 'props', and we get 'dispatch' from the props:
- let AddTodo = ({ dispatch }) => {
Then we will create a container component with connect that will inject that the dispatch function as a prop, we will remove the context types because the component generated by connect function will take care of reading this chore from the context.
The first argument to the connect function is map straight to props, but there aren't any props for at to-do component that depend on the current state, so I return an empty object. The second argument to connect is map dispatch to props, but at to-do component doesn't need any callback props. It just accepts the dispatch function itself, so I'm returning it as a prop with the same name.
Finally, I'm calling the function for a second time to specify the component I want to wrap, in this case, AddTodo itself:
- AddTodo = connect(
- state => {
- return {};
- },
- dispatch => {
- return {dispatch};
- }
- )(AddTodo);
However, it is wasteful to even subscribe to this chore if we don't calculate any props from its state. So I'm replacing the mapStateToProps function with an null, which tells connect that there is no need to subscribe to this store.
Additionally, it's pretty common pattern to inject just the dispatch function. This is why if you specify null or any false value in connect as the second argument, you're going to get dispatch injected as a prop.
- AddTodo = connect(
- null,
- null
- )(AddTodo);
In fact, I can just remove all arguments here. The default behavior will be to not subscribe to this chore and to inject just the dispatch function as a prop.:
- AddTodo = connect()(AddTodo);
So the AddTodo function would looks like:
- let AddTodo = ({ dispatch }) => {
- let input;
- return (
- <div>
- <input ref={node => {
- input = node;
- }} />
- <button onClick={() => {
- dispatch({
- type: 'ADD_TODO',
- id: nextTodoId++,
- text: input.value
- })
- input.value = '';
- }}>
- Add Todo
- </button>
- </div>
- );
- };
- AddTodo = connect()(AddTodo);
The AddTodo component that I declare accepts dispatch as a prop, but it doesn't know how to get this store. It just hopes that someone is going to pass the dispatch to it.
The connect code without any arguments is going to generate a container component that does not subscribe to this store. However, that will pass dispatch to the component that it wraps. In this case, it wraps my AddTodo component.
The second connect call returns the generated container component. I'm assigning it to AddTodo. I'm reassigning the let binding the second time.
------------------
Code:
- 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.context;
- this.unsubscribe = store.subscribe(() =>
- this.forceUpdate()
- );
- }
- componentWillUnmount() {
- this.unsubscribe();
- }
- render() {
- const props = this.props;
- const { store } = this.context;
- const state = store.getState();
- return (
- <Link
- active={
- props.filter ===
- state.visibilityFilter
- }
- onClick={() =>
- store.dispatch({
- type: 'SET_VISIBILITY_FILTER',
- filter: props.filter
- })
- }
- >
- {props.children}
- </Link>
- );
- }
- }
- FilterLink.contextTypes = {
- store: React.PropTypes.object
- };
- const Footer = () => (
- <p>
- Show:
- {' '}
- <FilterLink filter='SHOW_ALL'>
- All
- </FilterLink>
- {', '}
- <FilterLink filter='SHOW_ACTIVE'>
- Active
- </FilterLink>
- {', '}
- <FilterLink filter='SHOW_COMPLETED'>
- 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>
- );
- const { connect } = ReactRedux;
- let nextTodoId = 0;
- let AddTodo = ({ dispatch }) => {
- let input;
- return (
- <div>
- <input ref={node => {
- input = node;
- }} />
- <button onClick={() => {
- dispatch({
- type: 'ADD_TODO',
- id: nextTodoId++,
- text: input.value
- })
- input.value = '';
- }}>
- Add Todo
- </button>
- </div>
- );
- };
- AddTodo = connect()(AddTodo);
- 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
- );
- }
- }
- const mapStateToTodoListProps = (state) => {
- return {
- todos: getVisibleTodos(
- state.todos,
- state.visibilityFilter
- )
- };
- };
- const mapDispatchToTodoListProps = (dispatch) => {
- return {
- onTodoClick: (id) => {
- dispatch({
- type: 'TOGGLE_TODO',
- id
- });
- }
- };
- };
- const VisibleTodoList = connect(
- mapStateToTodoListProps,
- mapDispatchToTodoListProps
- )(TodoList);
- const TodoApp = () => (
- <div>
- <AddTodo />
- <VisibleTodoList />
- <Footer />
- </div>
- );
- const { Provider } = ReactRedux;
- const { createStore } = Redux;
- ReactDOM.render(
- <Provider store={createStore(todoApp)}>
- <TodoApp />
- </Provider>,
- document.getElementById('root')
- );
[Redux] Generating Containers with connect() from React Redux (AddTodo)的更多相关文章
- [Redux] Generating Containers with connect() from React Redux (VisibleTodoList)
Learn how to use the that comes with React Redux instead of the hand-rolled implementation from the ...
- [Redux] Generating Containers with connect() from React Redux (FooterLink)
Code to be refactored: class FilterLink extends Component { componentDidMount() { const { store } = ...
- 使用react+redux+react-redux+react-router+axios+scss技术栈从0到1开发一个applist应用
先看效果图 github地址 github仓库 在线访问 初始化项目 #创建项目 create-react-app applist #如果没有安装create-react-app的话,先安装 npm ...
- React Redux Sever Rendering实战
# React Redux Sever Rendering(Isomorphic JavaScript) connect、applyMiddleware、thunk、webpackHotMiddleware
今天,我们通过解读官方示例代码(counter)的方式来学习react+redux. 例子 这个例子是官方的例子,计数器程序.前两个按钮是加减,第三个是如果当前数字是奇数则加一,第四个按钮是异步加一( ...
- react+redux教程(五)异步、单一state树结构、componentWillReceiveProps
今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...
- react+redux教程(四)undo、devtools、router
上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...
- react+redux+generation-modation脚手架添加一个todolist
当我遇到问题: 要沉着冷静. 要管理好时间. 别被bug或error搞的不高兴,要高兴,又有煅炼思维的机会了. 要思考这是为什么? 要搞清楚问题的本质. 要探究问题,探究数据的流动. TodoList ...
- 实例讲解基于 React+Redux 的前端开发流程
原文地址:https://segmentfault.com/a/1190000005356568 前言:在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 s ...
随机推荐
- C++空类中的默认函数
定义一个空的C++类,例如 class Empty { } 一个空的class在C++编译器处理过后就不再为空,编译器会自动地为我们声明一些member function,一般编译过去就相当于 cla ...
- [Immutable.js] Lightning Fast Immutable.js Equality Checks with Hash Codes
While Immutable.js offers .is() to confirm value equality between iterables it comes at the cost of ...
- QOdbc 读写 excel
).toString(); ).toInt(); qDebug()<< name << age <<endl; } // 关闭数据库 db.close(); } i ...
- js 代码命名规范系列
在微博上看到一个段子 “老子哪天出任ceo迎娶白富美走上人生巅峰之后,一定要雇两个长腿大熊的妹子.一个帮我想变量名字,一个帮我想git commit的message!” 可以看出 命名方方面面的问题困 ...
- Android 加速Gradle构建项目
1. 升级gradle 进入项目文件夹$project/gradle/wrapper/gradle-wrapper.properties, 使用最新的gradle. 修改替换为最新的 distribu ...
- 关于android的SQLiteDatabase和Cursor的一些疑问
android数据库操作的基础有三个类:SQLiteOpenHelper,SQLiteDatabase和Cursor.其中,SQLiteOpenHelper会建立一个数据库连接,它虽然可以调用多次ge ...
- 【转载】ADO.NET与ORM的比较(4):EntityFramework实现CRUD
[转载]ADO.NET与ORM的比较(4):EntityFramework实现CRUD 说明:个人感觉在Java领域大型开发都离不了ORM的身影,所谓的SSH就是Spring+Struts+Hiber ...
- java之package与import
我就以package与import开始吧. package的作用其实就是c++的namespace的作用,防止名字相同的类产生冲突,只是实现的机制不一样,java编译器在编译时,直接根据package ...
- (原)Ubuntu16中编译caffe
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5797526.html 参考网址: http://caffe.berkeleyvision.org/in ...
- where和having的区别
1.用的地方不一样 where可以用在select update delete insert......into语句中 having只能用在select语句中 2.执行顺序不一样 where的搜索条 ...