背景
脱离了 Vue
,最近几个月一直接在使用新版 React
来搞低代码平台,那真是找到了初恋的感觉。由于代码平台的超高复杂度及 React
其完备的生态,使用 React 的技术栈应该算是最佳选择。上一次使用 React
已经是 4 年前的事了(转到我四年前写的一个 Repo《https://github.com/nelsonkuang/ant-admin》),那其实只是我当前的无心插柳之作,居然吸到了不少粉。话说回来,新版的 React
变化确实有点大,但感觉有种万变不离其中的感觉。最近三年一直使用的是 Vue 2
,中途 React Hook
发布时,已经学习了一轮 Hook
,加上近其也入门了下 Vue 3
,重新入手新版 React
,感觉没啥难度。
告别 Vue
再投身 React
Vue
的 Watch
对标 React
的 useEffect
useEffect
可以一次 watch
更多变量,使用起来更加灵活,代码如下:
useEffect(() => { // 处理自定义事情 }, [variable1, variable2, variableX]); // 被 watch 的对象
注:如果不传任何变量或者,传空数组,则等效于 React
的 componentDidMount
或者 Vue
的 onMount
。
另外:如果结合 return
还可以处理一些初始化 / 重置的操作;如下
例子一 – Dom 事件绑与解绑:
useEffect(() => { const listenerCallback = (e) => { // ... 自定义操作 }; if (myVar) { window.addEventListener('resize', listenerCallback); } return () => window.removeEventListener('resize', listenerCallback); }, [myVar]);
例子二 – Tab 中给子组件初始化回显与重置:
useEffect(() => { if (visible) { if (val1) { setTabCurrKey('1'); setTab1SelectedKeys([...val1]); } else if (val2) { setTabCurrKey('2'); setTab2SelectedKeys([...val2]); } else if (val3) { setTabCurrKey('3'); tap3Ref.current?.setFieldsValue({ key1: val3.key1, key2: val3.key2, key3: val3.key3, }); } } return () => { setTab1SelectedKeys([]); // 重置 tab1 数据 setTab2SelectedKeys([]); // 重置 tab2 数据 tap3Ref.current?.resetFields(); // 重置 tab3 数据 }; }, [visible, val1, val2, val3]);
Vue
的 Computed
对标 React 的 useMemo
效果差不多,废话不多说,先看代码:
const myComputedData = useMemo(() => { let result; // 处理自定义计算 // 如: result = variable1 + variable2 + variableX; return result; }, [variable1, variable2, variableX]);
Vue
的 ref
对标 React
函数组件的 ref
直接操控
React
的函数组件 ref
操作起来相对麻烦点。当然如果是 React
的类组件使用 ref
其实与 Vue
差不多。但现在还在用 React
组件的写法已经不香了。所以麻烦点也是值得的,主要依赖于:wrappedComponentRef
, useRef
, useImperativeHandle
, forwardRef
。代码如下:
// 子组件 const ChildComp = forwardRef((props, ref) => { // ... 其它代码 useImperativeHandle(ref, () => ({ // 供父组件使用的函数 outFn1: () => { // 这里编写自定义代码 return xxx; }, // 供父组件使用的变量 outData1, outData2, outDataX, })); return ( <> <div>content1</div> <div>content2</div> </> ); }); // 父组件 const ParentComp = (props) => { const childRef = useRef({}); // mouted 或者按需时使用子组件传过来的变量或者函数 useEffect(() => { const { outData1, outData2, outDataX, outFn1, } = childRef.current; // 这里编写自定义代码 ... }, []); return ( <div className={style.parent}> <ChildComp wrappedComponentRef={childRef} ref={childRef} // 兼容旧的 react 版本 /> </div> ); };
Vue
的 vuex
对标(来源于) React
使用的 Redux
Vue 中使用 Vuex 的五个基本属性分别为:state
、getters
、 mutations
、actions
、modules
。
React 中使用 Redux 可以对标的五个基本属性:state
、selectors / reselect
、reducer
、actions
、combineReducers
(类似,但有点区别)
Vue 与 React 组件之间通讯的差异不大
Vue 中组件之间主要通讯方式:
1、(父子)Props
传递 + watch
;
2、(子父)Props
或者 this.$emit
传,v-on
接收;
3、EventBus
通过 new Vue()
全局方式,Event.$emit
与 Event.$on
实现通讯;
4、Vuex
全局数据共享;
5、(父控子)Ref
方式直接执行;
6、(父子 / 父孙)provide
/ inject
。
React 中组件之间主要通讯方式:
1、(父子)Props
传递 或者 hooks
方式;
2、(子父)Props
或者 hooks
方式,如 useEffect
;
3、也可以创建 emitter
全局方式,emitter.emit
与 emitter.on
实现通讯;
4、Redux
全局数据共享;
5、(父控子)Ref
方式直接执行;
6、(父子 / 父孙)React.createContext
中的 Provider
与 Consumer
实现值传递。
Vuex
的 template
对标 React
的 Jsx
个人更喜欢 Jsx 的条件渲染及其强大更加灵活的模板渲染能力。在写 Jsx 时你可以无缝接入 js 的思维来写界面,你可以递归渲染、你可以使用三元运算进行条件渲染、你可以使用 js 的数组方法如:map
行进行循环沉浸、你可以使用各个自定义函数进行界面拼装,而不是局限于使用 Vue template
中的 v-if / v-for
等进行界面渲染。
说到这里不得不说 React Hook
对标 Vue 2.x 其实是算是一种代码组织方式或者是一种设计模式如 Vue 的 Mixin
或者 Vue 跟进的 Hook。由最底层来看,Hook
其实顾名思义是一个勾子,一个函数,创建了一个 React 组件组件闭包,返回一些变量或者函数供 React 组件内部使用,由于使用了一系列 Reactive
的变量数据的变动及流量都是响应式的,非常灵活方便。
Last but Not least
由于时间仓促,虽然还有很多有意思的东西可以继续分享,下回有时间继续写吧,最近太忙了。先抛出一些有趣的主题如:Prop spreading
、React 中如何对标 Vue 的 Component
is
动态组件的实现(直接把组件 map 到 redux 中使用 / 或者导出成一个 map 来使用)、对标 Vue 中的 /deep/
时 React 如何覆盖子组件的样式(使用 :global
)、React 中 setState / useState 中的设值是异步的如何类同步的方式获取最新值(使用 ref
ref.current = targetState
)、useEffect
中使用 / 不使用 return
场景、useState
hook 自定义 setState
函数(数组第二个参数)的使用场景等等。更多 react 常见问题可查看我另一篇博客《React 使用过程中常见问题 II》。