echarts中resize事件监控实例入门redux
背景
项目背景是通过react
+redux
完成不同组件之间的通信。
左侧导航栏有收缩时候右侧内容中echarts
图表能监测到此动作,并做resize
动作,具体实现效果
我们知道监听echarts
的resize()
方法可以通过window
的窗口监听事件
window.addEventListener('resize', this.chartResize)
但是这里可以看出,窗口大小是没有变化的,只是图表局部DOM
的宽度发生了变化,所以window
的窗口监听事件并不生效。可以通过监听当前图表DOM
的宽高来实现,或者我们从侧边的导航来着手。
这里导航和echarts
是两个不同的组件,且不是直接的父子组件的关系,因此考虑使用redux
来实现
实现
redux,react-redux
下载所需依赖包
npm i redux react-redux
actions
从名字看的出来,actions
就是为了存储我们的动作类型
在./src
目录下新建./src/actions/index.js
,内容
// actions/index.js
export const MenuCollapse = 'MenuCollapse'
用来存储所有可能派发(dispatch
)的类型(type
)。
reducer
在./src
目录下新建./src/reducers/index.js
import { MenuCollapse } from '../actions'
const initState = {
collapseVal: false
}
const AppReducer = (state=initState, action) => {
switch (action.type) {
case MenuCollapse: {
return {
collapseVal: action.value
}
}
default: {
return state
}
}
}
export default AppReducer
store
从名字我们看出,store
就是用来存储的,存储什么呢?存储我们的state
。
在./src
目录下新建./src/store/index.js
import { createStore } from 'redux'
import AppReducer from '../reducers'
const store = createStore(AppReducer)
export default store
这里可以模拟一下createStore
源码来更清晰的理解一下store
的作用
// 以下代码示例来自redux官方教程
const createStore = (reducer) => {
let state;
let listeners = [];
// 用来返回当前的state
const getState = () => state;
// 根据action调用reducer返回新的state并触发listener
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
/* 这里的subscribe有两个功能
* 调用 subscribe(listener) 会使用listeners.push(listener)注册一个listener
* 而调用 subscribe 的返回函数则会注销掉listener
*/
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
};
};
return { getState, dispatch, subscribe };
};
这里我的项目内容比较简单,所以reducer我只写了一个文件,如果你需要写多个reducer模块,参考下面这种store内容
import { createStore, combineReducers } from 'redux'
import xxxReducer from '../reducers/xxx.js'
import kkkReducer from '../reducers/kkk.js'
const reducer = combineReducers({
xxx: xxxReducer,
kkk: kkkReducer
})
// 这里需要对象的形式
const store = createStore(reducer)
export default store
store注入项目
在index.js
文件中,引入我们的store
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>,
document.getElementById('root')
)
派发事件dispatch
在导航组件app-menu.js
中,在发生收缩动作时派发事件
import store from '../../store'
import { MenuCollapse } from '../../actions'
/* 是否收起菜单栏 */
menuToLeft = () => {
store.dispatch({type: MenuCollapse, value: false})
this.setState({ menuWidth: 0 })
}
menuToRight = () => {
store.dispatch({type: MenuCollapse, value: true})
this.setState({ menuWidth: '220px' })
}
或者我们用connect
import { connect } from 'react-redux'
import { MenuCollapse } from '../../actions'
menuToLeft = () => {
this.props.menuCollapseDispatch(false)
this.setState({ menuWidth: 0 })
}
menuToRight = () => {
this.props.menuCollapseDispatch(true)
this.setState({ menuWidth: '220px' })
}
const mapStateToProps = () => { return {} }
// 从名字也能看出来就是将dispatch映射到了props上
const mapDispatchToProps = dispatch => {
return {
menuCollapseDispatch: value => dispatch({type: MenuCollapse, value})
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AppMenu)
监听store中值
此时我们收缩导航store
里面的值已经发生变化了,我们可以在其他组件中通过
store.getState()
来得到,但是这里我们是需要监听这个值发生变化做下一步操作,用到的是subscribe()
。
在图表组件line-bar-show.js
文件中
componentDidMount () {
window.addEventListener('resize', this.chartResize)
store.subscribe(() => {
// store.subscribe用来监听store中state
// 菜单动画有300ms,所以延迟器时长必须大于等于这个时间
this.chartResize()
})
}
chartResize = () => {
this.echartResizeTimer = setTimeout(() => {
this.echartsObj && this.echartsObj.resize()
}, 300)
}
componentWillUnmount () {
window.removeEventListener('resize', this.chartResize)
this.echartResizeTimer = null
this.loopTooltipTimer = null
}
注意: 这里需要注意的菜单收缩动画时间为300ms,但是值的变化时瞬间的,所以需要在监听到值变化以后延迟300ms再resize
图表。
这里的几个变量我都没有定义在组件的state
中,而是直接定义在组件上,跟state
平级,所以这里是通过=
来赋值的,而不是通过setState()
来赋值。
版本号
"echarts": "^4.7.0",
"redux": "^4.0.5",
"react-redux": "^7.2.2",