再次遇见 React 找回初恋的感觉

背景

脱离了 Vue,最近几个月一直接在使用新版 React 来搞低代码平台,那真是找到了初恋的感觉。由于代码平台的超高复杂度及 React 其完备的生态,使用 React 的技术栈应该算是最佳选择。上一次使用 React 已经是 4 年前的事了(转到我四年前写的一个 Repo《https://github.com/nelsonkuang/ant-admin》),那其实只是我当前的无心插柳之作,居然吸到了不少粉。话说回来,新版的 React 变化确实有点大,但感觉有种万变不离其中的感觉。最近三年一直使用的是 Vue 2,中途 React Hook 发布时,已经学习了一轮 Hook,加上近其也入门了下 Vue 3,重新入手新版 React,感觉没啥难度。

告别 Vue 再投身 React

VueWatch 对标 ReactuseEffect

useEffect 可以一次 watch 更多变量,使用起来更加灵活,代码如下:

 useEffect(() => {
    // 处理自定义事情
  }, [variable1, variable2, variableX]); // 被 watch 的对象

注:如果不传任何变量或者,传空数组,则等效于 ReactcomponentDidMount 或者 VueonMount
另外:如果结合 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]);
VueComputed 对标 React 的 useMemo

效果差不多,废话不多说,先看代码:

  const myComputedData = useMemo(() => {
    let result;
    // 处理自定义计算
    // 如: result = variable1 + variable2 + variableX;
    return result;
  }, [variable1, variable2, variableX]);
Vueref 对标 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>

  );
};
Vuevuex 对标(来源于) React 使用的 Redux

Vue 中使用 Vuex 的五个基本属性分别为:stategettersmutationsactionsmodules
React 中使用 Redux 可以对标的五个基本属性:stateselectors / reselectreduceractionscombineReducers(类似,但有点区别)

Vue 与 React 组件之间通讯的差异不大

Vue 中组件之间主要通讯方式
1、(父子)Props 传递 + watch
2、(子父)Props 或者 this.$emit 传,v-on 接收;
3、EventBus 通过 new Vue() 全局方式,Event.$emitEvent.$on 实现通讯;
4、Vuex 全局数据共享;
5、(父控子)Ref 方式直接执行;
6、(父子 / 父孙)provide / inject

React 中组件之间主要通讯方式
1、(父子)Props 传递 或者 hooks 方式;
2、(子父)Props 或者 hooks 方式,如 useEffect
3、也可以创建 emitter 全局方式,emitter.emitemitter.on 实现通讯;
4、Redux 全局数据共享;
5、(父控子)Ref 方式直接执行;
6、(父子 / 父孙)React.createContext 中的 ProviderConsumer 实现值传递。

Vuextemplate 对标 ReactJsx

个人更喜欢 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》。

作者: 博主

Talk is cheap, show me the code!