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)的更多相关文章

  1. [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 ...

  2. [Redux] Generating Containers with connect() from React Redux (FooterLink)

    Code to be refactored: class FilterLink extends Component { componentDidMount() { const { store } = ...

  3. 使用react+redux+react-redux+react-router+axios+scss技术栈从0到1开发一个applist应用

    先看效果图 github地址 github仓库 在线访问 初始化项目 #创建项目 create-react-app applist #如果没有安装create-react-app的话,先安装 npm ...

  4. React Redux Sever Rendering实战

    # React Redux Sever Rendering(Isomorphic JavaScript) ![React Redux Sever Rendering(Isomorphic)入门](ht ...

  5. react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware

    今天,我们通过解读官方示例代码(counter)的方式来学习react+redux. 例子 这个例子是官方的例子,计数器程序.前两个按钮是加减,第三个是如果当前数字是奇数则加一,第四个按钮是异步加一( ...

  6. react+redux教程(五)异步、单一state树结构、componentWillReceiveProps

    今天,我们要讲解的是异步.单一state树结构.componentWillReceiveProps这三个知识点. 例子 这个例子是官方的例子,主要是从Reddit中请求新闻列表来显示,可以切换reac ...

  7. react+redux教程(四)undo、devtools、router

    上节课,我们介绍了一些es6的新语法:react+redux教程(三)reduce().filter().map().some().every()....展开属性 今天我们通过解读redux-undo ...

  8. react+redux+generation-modation脚手架添加一个todolist

    当我遇到问题: 要沉着冷静. 要管理好时间. 别被bug或error搞的不高兴,要高兴,又有煅炼思维的机会了. 要思考这是为什么? 要搞清楚问题的本质. 要探究问题,探究数据的流动. TodoList ...

  9. 实例讲解基于 React+Redux 的前端开发流程

    原文地址:https://segmentfault.com/a/1190000005356568 前言:在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 s ...

随机推荐

  1. C++第15周(春)项目3 - OOP版电子词典(一)

    课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759.内有完整教学方案及资源链接 [项目3-OOP版电子词典](本程序中须要的相 ...

  2. [Regular Expressions] Find Groups of Characters, and ?:

    We'll capture groups of characters we wish to match, use quantifiers with those groups, and use refe ...

  3. [Protractor] Use protractor to catch errors in the console

    For any reason, there is an error in your code, maybe something like undefined error. Protractor sti ...

  4. el表达式判断是否相等

    <c:if test="${order.baofang eq 0 }"> 无包间 </c:if> <c:if test="${order.b ...

  5. Oracle 中的Pivoting Insert用法

    1.标准Insert --单表单行插入   语法:   INSERT INTO table [(column1,column2,...)] VALUE (value1,value2,...)      ...

  6. CPU性能测试

    用计算圆周率的办法来测试cpu性能 4*a(1) 是 bc 主動提供的一個計算 pi 的函數,至於 scale 就是要 bc 計算幾個小數點下位數的意思.當 scale 的數值越大, 代表 pi 要被 ...

  7. javascript父窗口与子窗口通信

    在父窗口的js代码 //回调的函数 function alt(temp){ alert(temp); }; $("#Btn").click(function (obj) { //声 ...

  8. [原创]VS2010中创建动态链接库及其调用

    [原创]VS2010中创建动态链接库及其调用 一.创建动态链接库 在VS2010中创建动态链接库的步骤如下: 1)生成->编译->生成MyDll 二.调用 当调用DLL中的方法,程序编译产 ...

  9. PyQuery基本操作介绍

    PyQuery基本操作介绍 PyQuery为Python提供一个类似于jQuery对HTML的操作方式,可以使用jQuery的语法对html文档进行查询操作. 本文以百度首页为例来介绍PyQuery的 ...

  10. debian 64位系统中添加对32位的支持

    dpkg --add-architecture i386 apt-get update apt-get install ia32-libs