做TodoList过程中的笔记
TodoList大概是最基础的入门例子了,基础,可是最重要的不就是基础么,不积跬步,何以至千里。眼高手低贻害无穷。看书,看教程好像是那么回事,“嗯,对我懂了”,也跟着敲出来了,“嗯,所以,我真的懂了”,真正到撇开书自己独立搞得时候,全白瞎。
但是还是得做不是,事情放在那儿它又不会自己解决,已经不能再拖了。
用react-redux撸的一个TodoList
其实早在一个星期前就已经第首次commit了,在教程的基础上加了个可以增加Todo类型的功能,想到加这个功能的原因是,苦于CSS样式的问题,就想找个CSS样式好看的TodoList应用模仿之,最后找了微软的To-do APP,然后这个APP有这个功能,就想着怎么实现,然后就很费力气的实现了。然后的结果是,由于什么样式都没加所以简直太踏马丑了,可是CSS始终让我觉得头疼,自觉CSS的理论基础还可以,但是实践真的难如登天,就因为这一个原因拖了一个星期,我不知道如果要照着To-do的动画效果仅让我用纯CSS码我估计会永远拖下去。
所以最终决定先找个UI框架来弄吧,还要跟react搭配的,最终找了Material-Ui。
好歹加了之后页面稍微能看了。
直接上预览。
废话一堆,下面才是与题目相关的
state tree的设计
设计,大概redux里最关键我觉得也是最难的就是这一块儿了,因为如果state tree妥了逻辑也差不多都分明了,可是对于我这个菜鸟来讲难度还是不小
{
header: {
isShowOptions: [boolean],
isShowClasses: [boolean]
},
todos: [
{
id: [an unique str or number],
text: [string],
complete: [boolean],
deleted: [boolean],
listName: [string] //the property by which to classify the todos
},
...
,
],
some: {
allList: [listName1, listName2, ..., ],
currentList: [string] //the current list
}
}
写完我发现,state tree居然这么简单的么(其实这块我应该也没花很久,主要让我蛋碎的是让人疼爱不已的CSS)。其中header
属性的两个子属性控制两个另外两个组件(其中一个暂时没用到)的显示;todos
的值是所有todo项,其中listName
这个子属性用来标识当前的todo项是属于哪一个类别的,显示的时候filter一下就可以只显示当前类别的todo了。但是这样的话后面删除某个类别时处理该类别下的todo项可能会有点麻烦;some
属性的allList
属性为当前所有的类别,currentList
属性,为当前显示todo项的类别。
最终完成上面初步的state tree过程中也是有遇到障碍的,比如在处理
some: {
allList: [listName1, listName2, ..., ],
currentList: [string] //the current list
}
的reducer的时候我不知道怎么办的,当时是这样处理的:
const allListReducer = (state=initValue, action) => {
switch (action.type) {
case ADD_CLASS: {
return [...state, action.listName]
}
default: {
return state
}
}
}
const currentListReducer = (state='To-do', action) => {
switch (action.type) {
case SET_CURRNT_CLASS: {
return action.listName
}
default: {
return state
}
}
}
const reducer = combineReducers({
allList: allListReducer,
currentList: currentListReducer
})
export default reducer
可能是当时觉得把两个不同类型的数据放在一个对象里处理不知道怎么下手,鬼使神差的就想到了用combineReducers
把两个reducer合并在一起然后再export出去。刚刚一直在想当初选择上面那种做法的理由,然后试了一下不用combineReducers
,直接处理,发现效果上是一样的,最终的state tree也是一样的。我想可能我当时就是不会把他们放在一起处理吧。下面是刚刚试的处理方法主要是通过...
操作符的来完成:
const initValue = {
allList: ['To-do', 'Important'],
currentList: "To-do"
}
const reducer = (state=initValue, action) => {
console.log(state, action)
switch(action.type) {
case ADD_CLASS: {
// return Object.assign({}, state.currentList, [...state.allList, action.listName])
return {...state, 'allList': [...state.allList, action.listName]}
}
case SET_CURRNT_CLASS: {
return {...state, 'currentList': action.listName}
}
default: {
return state
}
}
}
export default reducer
复杂度差不多,就是return那块各种...
可能一下子不能准确弄出来;相比于这个上面第一种的一个就一眼看下来就好理解一点。但是我不知道两种方式是不是完全等效,因为我记得combineReducer
处理方式不像上面第二种那样简单,每个reducer接受的state里只有与自己相关的那一部分数据,与其他recuder相关的数据则无法访问,而上面第二种只有一个reducer,故state必须包含所有数据。
对应的组件树也一样简单:
App :
- Header
- Todo
- Some(想半天不知道取什么名儿好,就随便叫了)
使用Material-Ui时遇到的一个问题
不是问题了。。。刚自己又看了下,原来是没用好API
一个CSS布局相关的问题
背景
需要通过按钮添加todo,同时按钮的位置随todo项的数量而改变,实现方案:1.todo项超过一定数量时自动进行分页(之前的react版实现过,但是代码不知道怎么没保存然后就没了,而且移动端分页似乎比较少见);2.让渲染todo列表的元素高度固定,增加垂直方向滚动条(实现的就是这个,但是默认滚动条太难看,待处理)
测试代码如下:
<style>
body {
margin: 0;
}
.wrapper {
position: relative;
height: 100vh;
}
ul {
margin: 0 auto;
height: 70vh;
overflow-y: auto;
}
ul li {
height: 6em;
margin-bottom: 1em;
background-color: #ccc;
}
.btn {
position: absolute;
bottom: 30px;
left: 0;
right: 0;
text-align: center;
}
</style>
</head>
<body>
<div class="wrapper">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<div class="btn">按钮所在位置</div>
</div>
但是实际中设计到长宽固定的貌似总是会麻烦一点也许要谨慎一些。像上面这个CSS布局的原理肯定是再基础不过的,可是我之前就是没写过这样的啊啊啊啊,完整的几个页面都没写过,天,我这样还怎么找工作哟。
最后
最后肯定又是要以一些无关的废话结尾话的,是的,没错。
拖延症太可怕了,国庆那老些天,原先预计要完成的一点没动,愣是各种找理由(比如要看S7的小组赛),国庆没了还拖了两天到现在。可是我都已经好几个月没工作了,再这么拖下去,估计要废了。
今天是开始与拖延症正面对肛的第一天,效果还不错,抵得上刚过去的七天了,可想而知之前那些日子是有多……
保持,再不紧张起来就饿死了。