重构前:
class ToDoView extends React.component{
....
render(){
....
return(
...
<ul>
{visibleTodo.map(todo=>(
<li key={todo.id}
onClick={()=>{
store.dispatch({
type:"TOGGLE_TODO",
id:todo.id
})
}}
style={{
textDecoration:
todo.completed?
'line-through':
'none'
}}>
{todo.text}
</li>
))}
</ul>
)
}
}
重构后:
const Todo = ({ //为什么要花括号?因为直接在参数中进行解构
text, //将要渲染的数据放进参数中
completed,
onClick //点击事件参数的命名有两种方式。1.onClick,表示该Todo行为更灵活 2.onToggleClick,表明该点击是一个特定行为
})=>(
<li
onClick={onClick}//这样修改后,todo的点击行为就灵活多了
style={{textDecoration:completed?'line-through':'none'}}
>
{text}
</li>
)
const TodoList = ({
todos,//和todo一样,将要传入的方法和参数作为参数传入组件,todoList只做展示
onTodoClick
})=>(
<ul>
{todos.map(todo=>
<Todo
key={todo.id}
{...todo}//{id: 1, text: "", completed: false} react传入state和对象解构
onClick = {()=>onTodoClick(todo.id)}
/>)
}
</ul>
)
...
class ToDoView extends React.component{
....
render(){
....
return(
...
<TodoList todos={visibleTodo}
onTodoClick={id=>store.dispatch({
type:"TOGGLE_TODO",
id
})}
...
)
}
}
1.表现组件,应当关注于视觉的展示,与行为相分离,具体执行什么功能,可以在调用的时候来决定
2.参数的传递不应当过深,比如Filter需要一个叫currentFilter的值,为了获得这个值,就要先传入Footer,再从Footer传入Filter,而Footer自身并不会使用到这个值。过深的另外一个弊端就是父组件需要知道子组件需要哪些值,这样就使得组件缺乏封装性。
3.构建容器。容器的作用是链接展示型组件与Redux Store,然后指定需要的数据和行为。注意,分离容器和展示型组件通常是一个好主意,但不要把这一点当做一个代码原则,除非这样做真的可以降低代码的复杂度,我建议先尝试抽离出展示型的组件,如果在属性传递时造成了太多重复性的代码,那就可以考虑创建一个容器来指定加载的数据和具体的行为