专注于前端开发, 追求更好的用户体验, 更好的开发体验 [长沙前端QQ群:234746733]

react 与 vue 的一些写法对比

在线 Playground 测试

state 简单状态

vue

const count = ref(0);
const increment = () => (count.value += 1);

react

const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);

state 复杂状态

vue

state = reactive({
  value: 0,
});
state.value = 1;

react

const [state, setState] = useReducer((prev, { ...next }) => ({ ...prev, ...next }), {
  value: 0,
});
setState({ value: 1 });

mounted 初始渲染

vue

onMounted(() => {
  console.log("mounted");
});

react

useEffect(() => {
  console.log("mounted");
}, []);

unmounted 被卸载

vue

onUnmounted(() => console.log("unmounted"));

react

useEffect(() => {
  // cleanup
  return () => {
    console.log("unmounted");
  };
}, []);

watch

vue

watch(
  [() => props.data],
  (data) => {
    console.log(data);
  },
  { immediate: true, deep: false }
);

react

// immediate watch
useEffect(() => {
  console.log(props.data);
}, []); // 空数组, 初始化时立即执行
// 常规 watch
useEffect(() => {
  console.log(props.data);
}, [props.data]);
// deep watch
useEffect(() => {
  console.log(props.data);
}, [JSON.stringify(props.data)]);
// deep watch2, 用 useRef 记录上一次的值, 然后再比较
const prevRef = useRef();
useEffect(() => {
  prevRef.current = props.data;
}, [props.data]);
useEffect(() => {
  if (!_.isEqual(prevRef, props.data)) {
    console.log("changed:", prevRef, props.data);
  }
}, [prevRef.current, props.data]);

watchEffect 立即执行, 并在依赖变化时执行

vue

watchEffect(() => {
  console.log(props.data);
});

react

useEffect(() => {
  console.log(props.data);
}, [props.data]);

computed 缓存值

vue

const name = computed(() => {
  return `${userName}`;
});

react

const name = useMemo(() => {
  return `${userName}`;
}, [userName]);

ref

vue

const elem = ref<HTMLElement>(); // elem.value
// template
<div ref="elem" />

react

const elem = useRef<HTMLElement>(); // elem.current
// jsx
<div ref={elem} />

父子组件通信

vue

// 通过props/attrs传递给子组件; 通过emit传递给父组件
// 父组件
<template>
<Child :name="'test'" @change="onChanged" />
</template>
// 子组件
<template>
<input :value="name" @input="handleChange" />
</template>
// <script setup>
const props = defineProps({
  name: String,
})
const attrs = useAttrs() // class/style/v-on
const emit = defineEmits(['change'])
const handleChange = (e) => {
  emit('change', e.target.value)
};

react

// 通过props传递数据和回调函数给子组件
// 父组件
<Child name={"test"} onChange={onChanged} />;
// 子组件
const Child = ({ name, onChange }) => {
  const handleChange = (e) => {
    onChange(e.target.value);
  };
  return <input value={name} onChange={handleChange} />;
};

Provide/Inject 子孙组件传值

vue

// 父组件
<template>
  <div>
    <Child />
  </div>
</template>

<script setup>
import { provide } from "vue";
provide("abc", "123");
</script>
// 子孙组件
<template>
  <div>
    {{ abc }}
  </div>
</template>
<script setup>
import { inject } from "vue";
const abc = inject("abc");
</script>

react

// context.ts
import { createContext } from "react";
export default createContext({});

// 父组件
import TestContext from "./context.ts";
const Parent = () => {
  return (
    <TestContext.Provider value="123">
      <Child />
    </TestContext.Provider>
  );
};
// 子孙组件
import { useContext } from "react";
import TestContext from "./context.ts";
const Child = () => {
  const abc = useContext(TestContext);
  return <div>{abc}</div>;
};

slot 插槽

vue

// 父组件
<template>
<Child>
  <template #default="slotProps">
    test {{ slotProps }}
  </template>
</Child>
</template>
// 子组件
<template>
<div>
  <slot name="default" v-bind="{ t: 1 }" />
</div>
</template>

react

// 父组件
<Child bind={(p) => JSON.stringify(p)}>test</Child>;
// 子组件
const Child = ({ children, bind }) => {
  return (
    <div>
      {children} {bind({ t: 1 })}
    </div>
  );
};

css

vue

// scoped
<template>
<div class="test" />
</template>
<style scoped>
  .test {}
</style>
// css module
<template>
<div :class="[$style.test]" />
</template>
<style lang="scss" module>
  .test {}
</style>
// vue3 还可以使用v-bind 绑定<script>中的变量

react(css module)

import styles from "./Test.module.scss";
const Test = (props) => <div className={styles.test} />;

更推荐 css module 方案, react/vue 可复用

/ 分类: 开发 / TrackBackhttps://xhl.me/archives/react-vue/trackback标签: react, vue

添加新评论 »