Redux配合React的简单应用
之前正在重构VocaloidInfo网易云插件,用到了Typescript+React,正好拿出来水一水
需求是这样的:
用户打开歌曲页面时,从VocaDB抓取数据,因为抓取需要一定的时间,所以在结果返回之前要显示一段文字
结果返回之后,要把这段文字更新成数据
用户切换歌曲之后也要刷新数据
显示文字的部分就用React组件来完成,但是需要对里面的数据进行更新,所以使用redux做个简易的更新
Redux部分
Action
Action可以解释为 更改数据(state)的一种行为,拥有两个属性 type
和 data
,理论上来说我们应该通过Reducer对action的type进行判断,然后决定如何通过data更新state
比如一个int类型的state,有两种type add
和 minus
。如果type为 add
就让state加上data,如果type为 minus
就让state减去data
Reducer
Reducer是一个函数,他接受state和action,返回新的state
在Reducer中我们需要对action的 type
进行判断,再通过action的 data
对state进行处理,然后返回新的state
Store
store就是Redux的数据储存器,他负责储存state,当调用他的 dispatch
方法时,他通过自己的reducer和dispatch方法参数中的action来更新state
实战
这里需要实现一个歌曲信息的Store,
由于我的需求比较特殊,歌曲的数据其实需要的时间很短,换一首歌之后原来的数据就不用了,而且action中的type和data我的react组件都要用到,所以我决定直接抛弃state,直接把action当成state里面给React组件用
代码具体如下:
import { configureStore, Action } from "@reduxjs/toolkit"; //导包
// 这边定义了SongAction的三种type
export enum SongActionType {
LOADING, //歌曲数据正在加载中
LOADED, //歌曲数据已经加载完毕
FAILED, //没有找到歌曲数据
ALL = LOADING | LOADED | FAILED
}
// 定义SongAction
export interface SongAction extends Action {
type: SongActionType,
data: {
vocadbData: any, //歌曲的vocadb数据
bilibiliData?: any //歌曲的bilibili数据
}
}
// 定义reducer
const reducer = ( _, action: SongAction) => { //第一个参数中的下划线其实应该是state, 只不过我不需要所以就把它扔了,直接把原始的action分发下去
return action;
}
// 创建store
export const SongInfoStore = configureStore({ reducer: reducer });
Redux部分到此结束。
React部分
React部分需要对store进行订阅实现数据更新,这里直接贴代码:
// 歌曲数据的React组件
export default abstract class DefaultSongInfo extends React.Component<{store: Store<SongAction> }> {
// 通过store的subscribe方法订阅数据,实现更新
componentDidMount(): void {
this.props.store.subscribe(() => {
this.forceUpdate();
});
}
render() {
const store = this.props.store;
const action = store.getState();
// 接下来就是根据action对应的渲染数据,不多展开了
}
}
想要渲染这个组件的话就用以下代码 (ReactDOM):
ReactDOM.render(<DefaultSongInfo { ...{store: SongInfoStore} }>, 挂载点);
更新数据
使用 dispatch
方法更新数据:
抓取数据前:
SongInfoStore.dispatch( {type: SongActionType.LOADING } );
成功抓取数据:
SongInfoStore.dispatch( { type: SongActionType.LOADED , data: data } )
如果失败了:
SongInfoStore.dispatch( {type: SongActionType.FAILED } );