一、使用umi搭建项目,为什么约定式路由无法使用?
.umirc.(ts|js)文件中对 router 进行了配置,约定式路由将失效、新添的页面不会自动被 umi 编译,umi将使用配置式路由。
解决办法:进入.umirc.(ts|js)文件,注释掉router
// routes: [
// { path: '/', component: '@/pages/index' },
// ],
二、在组件挂载时,执行的函数:
useEffect(() => {
props.dispatch({
type: 'task/getTodo',
})
}, [])
一定要注意:要先建立connect
import { connect } from 'dva'
const myStateToProps = (state: any) => {
return {
todos: state.task.todos
}
}
export default connect(myStateToProps)(List)
与之建立联系的是models文件下的文件
⚠️ reducers中一定要返回完整的state,不能只返回state中的todos
import * as apis from '../services/task.js'
export default {
namespace: 'task',
state: {
todos: [],
},
reducers: {
setTodo(state, payLoad) {
console.log(payLoad.data.todos)
let _state = JSON.parse(JSON.stringify(state))
_state.todos = payLoad.data.todos
// 这里一定要返回完整的state,不能只返回todos
return _state
}
},
effects: {
*getTodo({payLoad}, {put, call}) {
let rel = yield call(apis.getTodo)
if(rel.data) {
yield put({
type: "setTodo",
data: rel.data.data
})
}
}
}
}
之后通过props.todos拿到数据
<ul>
{
props.todos.map((todoObj: any) => {
return <h4>{todoObj.id},{todoObj.assignment}</h4>
})
}
<li> 3 已完成 / 6 总数</li>
</ul>
三、针对tudoList案例,触及li 标签,就会在所有的li中都触发mouseEnter
const [mouse, setMouse] = useState<boolean>(false)
const handleEnter = (flag: boolean) => {
setMouse(flag)
}
const handleLeave = (flag: boolean) => {
setMouse(flag)
}
<ul className={styles.todo} >
{
props.todos.map((todoObj: any) => {
return (
<li key={todoObj.id} onChange={handleState}
onMouseEnter={() => {handleEnter(true)}} onMouseLeave={() => {handleLeave(false)}}
className={todoObj.state ? styles.task11 : styles.task22}>
<div >
<label >
<input type="checkbox" defaultChecked={todoObj.state} value={todoObj.id}
/>{todoObj.assignment}
</label>
<button className={styles.delete}
// style={{display: mouse? 'block': 'none'}}
onClick={() => {handleDelete(todoObj.id)}}>删除</button>
</div>
</li>
)
})
}
<li>已完成 {wellDone} / 总数 {props.todos.length}</li>
</ul>
解决办法1:不使用onMouseEnter,改用hover选择器:hover
鼠标未移入,display:none;
鼠标移入:display:inline;
.todo li:hover div button {
display: inline;
background-color: red;
border: 0;
flex: 1;
width: 50px;
margin-right: 15px;
}
.todo li div button {
display: none;
}
解决办法2:单独针对button来做展示与不展示
<li className={styles.li}>
<label className={styles.label}>
<input className={styles.input} type="checkbox" defaultChecked={done}
onChange={handleCheck1} />
<span className={styles.task}
style={{ textDecoration: done ? 'line-through' : '', color: done ? 'red' : 'black' }}
>{task}</span>
</label>
<span className={styles.btndiv}>
<button className={styles.btnDanger} style={{ display: flag ? '' : 'none' }}
onClick={() => handleDelete(id)}>删除</button>
</span>
</li>
四、删除按钮的格式:如何使删除按钮在一个固定的位置?
使用flex布局,父元素display:flex布局,子元素通过flex的分配来固定位置
.todo li {
height: 30px;
display: flex;
}
.todo li:hover div button {
display: inline;
flex: 1;
}
.task11 div label {
text-decoration: line-through;
flex: 6;
}
五、保存任务后,清空任务栏
input中 使用 value={value}:受控组件
onChange在内容发生改变时,触发
注意⚠️:尽量不操作Dom,即使操作Dom,也最好使用refs;
const [value, setValue] = useState<string>('')
const handleChange = (e: any) => {
console.log(e.target.value)
setValue(e.target.value)
}
const handleTask = () =>{
if (value.trim()) {
props.dispatch({
type: 'task/setTodo',
data: {
todo: {value}
}
})
}
setValue('');
// 尽量不操作DOM,即使操作DOM,也最好使用refs
// var btn = document.getElementsByName('input')[0]
// console.log(btn)
// btn.value = ''
}
<div>
<div className={styles.footer} >
<h4 className={styles.task}>任务:</h4>
<input className={styles.input} // onKeyUp={handleInput}
type="text" placeholder="请输入新的任务" value={value} onChange={handleChange} />
</div>
<button onClick={handleTask} className={styles.btn}>保存任务</button>
</div>
六、注意点
使用:hover要和类名紧挨,不能有空格. li:hover => li :hover
.todo li:hover div button {
display: inline;
background-color: red;
}
.todo li:nth-of-type(1) {
border-top: 1px solid #000;
}
对于typeScript事件类型:
const handleChange = (e: React.MouseEvent<HTMLInputElement> ) => {
console.log(e.currentTarget.value)
setValue(e.currentTarget.value)
}