Step1: Footer 组件
FilterLink
组件的currentFilter
, onClick
等属性要得来回传递多次,而且更重要的是定义组件的的时候onClick
等事件与该组件要得有更直观的依赖关系才行。
使用FilterLink
组件的时候要知道currentFilter
才可以调用,在最上层里调用时必须知道这个值才可以,所以Footer
里还要得接收visibilityFilter
的值才行。
这样以来父级层里要传递很多参数才可以使用。
首先调用Footer
的时候我们这样来修改,更直观一些
//修改前:
<Footer
visibilityFilter={visibilityFilter}
onFilterClick={filter => {
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter
});
}} />
//修改后:
<Footer />
这样Footer
组件就不用去管,visibilityFilter
和onFilterClick
// Footer 容器组件
//修改前:
const Footer = ({
visibilityFilter,
onFilterClick
}) => (
<p>
Show:
{' '}
<FilterLink
filter='SHOW_ALL'
currentFilter={visibilityFilter}
onClick={onFilterClick}>ALL</FilterLink>
{' '}
<FilterLink
filter='SHOW_ACTIVE'
currentFilter={visibilityFilter}
onClick={onFilterClick}>Active</FilterLink>
{' '}
<FilterLink
filter='SHOW_COMPLETED'
currentFilter={visibilityFilter}
onClick={onFilterClick}>Completed</FilterLink>
</p>
);
//修改后:
const Footer = () => (
<p>
Show:
{' '}
<FilterLink
filter='SHOW_ALL'>ALL</FilterLink>
{' '}
<FilterLink
filter='SHOW_ACTIVE'>Active</FilterLink>
{' '}
<FilterLink
filter='SHOW_COMPLETED'>Completed</FilterLink>
</p>
);
这样一来要得考虑FilterLink
怎么定义onClick
的行为和当前过滤状态了
//FilterLink 组件
//修改前:
const FilterLink = ({
filter,
children,
currentFilter,
onClick
}) => {
if (filter === currentFilter){
return <span>{children}</span>;
}
return (
<a href='#'
onClick={e => {
e.preventDefault();
onClick(filter);
}}>
{children}
</a>
);
}
//修改后: //分离数据只去管怎么展示
const Link = ({ //分离展示组件为Link
// filter,
active,
children,
// currentFilter,
onClick
}) => {
if (active){
return <span>{children}</span>;
}
return (
<a href='#'
onClick={e => {
e.preventDefault();
onClick(); //去掉filter
}}>
{children}
</a>
);
}
class FilterLink extends Component {
componentDidMount() { //React初始化渲染不会调用,更新后调用。
this.unsubscribe = store.subscribe(() => this.forceUpdate());
//forceUpdate说明:https://react.bootcss.com/react/docs/react-component.html#forceupdate
}
componentWillUnmount() {
this.unsubscribe(); //这个实在搞不懂是取消监听的还是更新状态用的~ OTL
}
render() {
const props = this.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>
);
}
}
对这一部分代码的目的不太理解查看原文慢慢理解吧。好像现在不更新状态也没什么问题。
class FilterLink extends Component {
componentDidMount() {
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
componentWillUnmount() {
this.unsubscribe();
}
}
render() { ... }
React provides a special forceUpdate method on the component instances to force their re-rendering. We're going to use it together with store.subscribe method so that any time the store state changes, we force update the container components.
We perform the subscription inside the componentDidMount lifecycle method. So it's important to unsubscribe inside the componentWillUnmount method. Note that we don't actually have the unsubscribe function, but this is the return value of the store subscribe method, so we can keep it, and then call it inside componentWillUnmount.
Step2: TodoList 容器组件
//修改前:
<TodoList
todos={getVisibleTodos(todos,visibilityFilter)}
onTodoClick={id =>
store.dispatch({
type: 'TOGGLE_TODO',
id
})
} />
//修改后:
<VisibleTodoList />
class VisibleTodoList extends Component {
componentDidMount() { //React初始化渲染不会调用,更新后调用。
this.unsubscribe = store.subscribe(() => this.forceUpdate());
//forceUpdate说明:https://react.bootcss.com/react/docs/react-component.html#forceupdate
}
componentWillUnmount() {
this.unsubscribe(); //这个实在搞不懂是取消监听的还是更新状态用的~ OTL
}
render() {
const props = this.props;
const state = store.getState();
return (
<TodoList
todos={
getVisibleTodos(
state.todos,
state.visibilityFilter
)
}
onTodoClick={id =>
store.dispatch({
type: 'TOGGLE_TODO',
id
})
}
/>
);
}
}
Step3: AddTodo 组件
//修改前:
<AddTodo
onAddClick={text =>
store.dispatch({
type: 'ADD_TODO',
id: nextTodoId++,
text
})
}
/>
//修改后:
<AddTodo />
//AddTodo 组件
const AddTodo = () => {
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>
);
};
Step4: TodoApp组件
// TodoApp 组件
//修改前:
const TodoApp = ({
todos,
visibilityFilter
}) => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);
const render = () => {
ReactDOM.render(
<TodoApp {...store.getState()} />,
document.getElementById('root')
);
};
store.subscribe(render);
render();
//修改后:
const TodoApp = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);
ReactDOM.render(
<TodoApp />,
document.getElementById('root')
);
//最终代码:http://jsbin.com/bocevor/edit?js,output
异步请求
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
https://github.com/dwqs/blog/issues/35