1、理解 useEffect
- 理解
useEffect
需要抛弃生命周期这条知识点。 Hooks
设计思想内没有生命周期概念,我认为它更像监听更新的勾子函数。- 页面
render
时,执行useEffect
函数。
举个栗子:
- 获取用户数据并加载。
执行1次
- 修改姓名并保存。
执行n次
const initName = undefined // 姓名
export default () => {
const [name, setName] = useState(initName)
useEffect(() => {
Get.defaultUserInfor()
}, [false])
// [false] => 填入 [常量] 只在页面初次加载时执行一次。
useEffect(() => {
Post.submitUserInfor(name)
}, [name])
// [name] => 监听 [变量] 有更新则执行函数。
return (
<div>
<p>
姓名:
<input value={name} onChange={val => setName(val) } />
</p>
</div>
)
}
2、繁索的 useState
- 调用
useState
返回两个值:初始值 和 set函数。 - 可以在
useState(默认值)
调用时初始一个默认值。 - 每创建一个变量则调用一次,n 个变量需要调用 n次。
举个栗子【扩展:增加年龄信息】:
- 获取用户数据并加载。
执行1次
- 修改姓名并保存。
执行n次
- 修改年龄并保存。
执行n次
const initName = undefined // 姓名
const initAge = 0 // 年龄
export default () => {
const [name, setName] = useState(initName)
const [age, setAge] = useState(initAge)
useEffect(() => {
Get.defaultUserInfor()
}, [false])
// [false] => 填入 [常量] 只在页面初次加载时执行一次。
useEffect(() => {
Post.submitUserInfor({ name, age })
}, [name, age])
// [name, age] => 监听 [变量一, 变量二] 有更新则执行函数。
return (
<div>
<p>
姓名:
<input value={name} onChange={val => setName(val) } />
</p>
<p>
年龄:
<input value={age} onChange={val => setAge(val) } />
</p>
</div>
)
}
举个栗子【扩展:增加保存按钮】:
- 获取用户数据并加载。
执行1次
- 修改姓名、年龄更新页面元素,但不发起请求。
执行n次
- 增加保存按钮,添加请求事件,保存用户信息。
执行n次
const initName = undefined // 姓名
const initAge = 0 // 年龄
const initInfor = { name: undefined, age: 0 } // 用户信息
export default () => {
const [name, setName] = useState(initName)
const [age, setAge] = useState(initAge)
const [infor, setInfor] = useState(initInfor)
useEffect(() => {
Get.defaultUserInfor()
}, [false])
// [false] => 填入 [常量] 只在页面初次加载时执行一次。
useEffect(() => {
Post.submitUserInfor(infor)
}, [{...infor}])
// [{...infor}] => 监听 [{...对象变量}] 有更新则执行函数。
// 解构-防止更新无法被监听。
return (
<div>
<p>
姓名:
<input value={name} onChange={val => setName(val) } />
</p>
<p>
年龄:
<input value={age} onChange={val => setAge(val) } />
</p>
<p>
<button onClick={() => { setInfor({ name, age }) }}>保存</buont>
</p>
</div>
)
}
3、优秀的 useReducer
useState
基因继承于useReducer
。- 实际在
useState
内部,也是调用useReducer
来创建新状态和set函数。 useReducer(函数, 初始状态)
,接收 触发函数 和 当前应用state,执行结果并返回最新state。
举个栗子【扩展】:
- 获取用户数据并加载。
执行1次
- 修改姓名、年龄更新页面元素,但不发起请求。
执行n次
- 点击保存按钮,发送请求保存用户信息。
执行n次
// 集中管理 State 状态
// 初始化
const initialState = {
name: undefined, // 姓名
age: 0, // 年龄
infor: {}, // 用户信息
}
// 触发函数,相当于多个 setState 合集
const dispatch = (state, action) => {
switch(action.type)
case 'name':
return { ...state, name: action.payload }
case 'age':
return { ...state, age: action.payload }
case 'infor':
return { ...state, infor: action.payload }
default:
return state
}
export default () => {
const [state, dispatch] = useReducer(dispatch, initialState)
const { name, age, infor } = state
useEffect(() => {
Get.defaultUserInfor()
}, [false])
// [false] => 填入 [常量] 只在页面初次加载时执行一次。
useEffect(() => {
Post.submitUserInfor(infor)
}, [{...infor}])
// [{...infor}] => 监听 [{...对象变量}] 有更新则执行函数。
// 解构-防止更新无法被监听。
return (
<div>
<p>
姓名:
<input value={name} onChange={val => {
dispatch({
type: 'name',
payload: val
})
}} />
</p>
<p>
年龄:
<input value={age} onChange={val => {
dispatch({
type: 'age',
payload: val
})
}} />
</p>
<p>
<button onClick={() => {
dispatch({
type: 'infor',
payload: { name, age }
})
}}>保存</buont>
</p>
</div>
)
}
4、更好的方案
useReducer
与Class类
互补使用。Class类
用作管理状态和函数,作用类似数据模型
。useReducer
用作为视图层
注入实例。
举个栗子【扩展】:
- 获取用户数据并加载。
执行1次
- 修改姓名、年龄更新页面元素,但不发起请求。
执行n次
- 点击保存按钮,发送请求保存用户信息。
执行n次
- 拆分
state
管理文件model.js
。 视图层
引用model.js
并new
一个实例。
model.js
export default class Model {
// 集中管理 State 状态
// 初始化
initialState = {
name: undefined, // 姓名
age: 0, // 年龄
infor: {}, // 用户信息
}
// 触发函数,相当于多个 setState 合集
// 解构:相同 key键 新的 payload 会替换旧的 state
reducer(state, payload) {
return {
...state,
...payload,
}
}
// 赋予,将状态更新器 dispatch 写入该实例中
// 可以在实例中处理 state 并被 view 层捕获
assign(dispatch) {
this.dispatch = dispatch
}
// 派发,初始状态更新器
dispatch() { }
// GET请求
async getUserInfor() {
const res = await Get.defaultUserInfor()
if (res) {
this.dispatch({
name: res.data.name,
age: res.data.age,
})
}
}
// POST请求
async submitUserInfor(params) {
const res = await Post.submitUserInfor(params)
res && console.log('保存成功')
}
}
view.js
import Model from './model.js'
const $model = new Model() // 状态管理
export default () => {
const [state, dispatch] = useReducer($model.reducer, $model.initialState)
$model.assign(dispatch)
const { name, age, infor } = state
useEffect(() => {
$model.getUserInfor()
}, [false])
// [false] => 填入 [常量] 只在页面初次加载时执行一次。
useEffect(() => {
$model.submitUserInfor(infor)
}, [{...infor}])
// [{...infor}] => 监听 [{...对象变量}] 有更新则执行函数。
// 解构-防止更新无法被监听。
return (
<div>
<p>
姓名:
<input value={name} onChange={val => {
dispatch({ name: val })
}} />
</p>
<p>
年龄:
<input value={age} onChange={val => {
dispatch({ age: val })
}} />
</p>
<p>
<button onClick={() => {
dispatch({
infor: { name, age }
})
}}>保存</buont>
</p>
</div>
)
}
结语
学习 hook
并上手项目摸索的方案,依据个人代码习惯和思维进行目录的简单构建。
当然也还有很多值得优化的地方,比如:用 Class类
的继承 或 @装饰器
,抽离 触发
、派发
、赋予
3个函数方法;也可以完全脱离 dispatch
, 视图层
时实监听 model
层的变化。
自己也在不断学习中,有错误处或不合理处要积极指正哦!哈哈哈~