了解了这些你就掌握了 React(下)

1. 前言

本文将以 React 和 Vue3 进行同步对比,带大家快速掌握 React。这个系列分为上下两篇,上篇内容包括:

  • 组件
  • JSX
  • 插值
  • 数据通信
  • 渲染
  • 事件
  • 状态

下篇包括:

  • 元素引用
  • 跨级传值
  • Portals
  • Suspense
  • Error Boundaries
  • Hooks

2. 元素引用

想要引用HTML元素节点,在 Vue 中通过 ref 来实现,React 通过 useRef 钩子。

Vue:

ts 复制代码
const inputRef = ref(null);

onMounted(() => {
  if (inputRef) {
    inputRef.value.focus();
  }
});

<input type="text" ref="inputRef" />

React:

ts 复制代码
const inputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
  inputRef?.current?.focus();
}, []);

<input type="text" ref={inputRef} />

通过 .current 使用 ref 引用。

3. 跨级传值

Vue:

ts 复制代码
// App.vue
<script setup>
import { provide } from 'vue';
provide('theme', 'light');
</script>

<template>
  <ChildComponent />
</template>

// ChildComponent.vue
<script setup>
import { inject } from 'vue';
const theme = inject('theme');
</script>

<template>
  <div>当前主题:{{ theme }}</div>
</template>

React:

ts 复制代码
// 1. 创建一个Context
export const ThemeContext = createContext('light');

// 2. 在父组件(App.tsx)中使用 ThemeContext.Provider 包裹子组件,并传值
//<ThemeContext.Provider value="dark">
  <ChildComponent />
//</ThemeContext.Provider>

// ChildComponent.tsx
import { useContext } from 'react';
import { ThemeContext } from '../App'; // 3. 导入上下文

export default function ChildComponent() {
  // 使用 useContext 获取Context的值
  const theme = useContext(ThemeContext); // 4. 使用上下文中的数据

  return <div>当前主题:{theme}</div>;
}

如果父组件没有提供 <ThemeContext.Provider>,将会使用默认值 light。

4. Portals

传送门,Vue3提供了内置组件<Teleport>,而在 React 中使用的是 createPortal

Vue:

ts 复制代码
<template>
  <div>
    <teleport to="body">
      <p>hello</p>
    </teleport>
  </div>
</template>

React:

ts 复制代码
import { createPortal } from 'react-dom';

export default function App() {
	return (
		<div>
			{createPortal(<p>hello</p>, document.body)}
		<div>
	)
}

5. Suspense

Vue:

ts 复制代码
<template>
  <Suspense>
    <template #default>
      <AsyncComponent />
    </template>
    <template #fallback>
      <p>Loading...</p>
    </template>
  </Suspense>
</template>

<script setup>
import { defineAsyncComponent, Suspense } from 'vue';

const AsyncComponent = defineAsyncComponent(() =>
  import('./AsyncComponent.vue')
);
</script>

React:

ts 复制代码
import React, { Suspense } from 'react';

const AsyncComponent = React.lazy(() => import('./AsyncComponent'));

function App() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <AsyncComponent />
    </Suspense>
  );
}

export default App;

6. Error Boundaries

边界错误处理。

Vue:

ts 复制代码
app.config.errorHandler = (err, instance, info) => {
  // 处理错误,例如:报告给一个服务
}

React:

ts 复制代码
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 更新状态,以便下一次渲染将显示后备 UI。
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // 示例"组件堆栈":
    //   在 ComponentThatThrows 中(由 App 创建)
    //   在 ErrorBoundary 中(由 APP 创建)
    //   在 div 中(由 APP 创建)
    //   在 App 中
    logErrorToMyService(error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // 你可以渲染任何自定义后备 UI
      return this.props.fallback;
    }

    return this.props.children;
  }
}

<ErrorBoundary fallback={<p>Something went wrong</p>}>
  <Profile />
</ErrorBoundary>

7. Hooks

7.1 State 状态

Vue:ref(), reactive()

ts 复制代码
const demoRef = ref('demo ref');
const demoRef2 = ref([1, 2, 3]);
const demoReactive = reactive({
  name: 'Alice',
  age: 18,
});

React:useState()

ts 复制代码
const [demoState, setDemoState] = useState();

7.2 Context 上下文

Vue:provide() + inject()

React:useContext()

7.3 Ref 引用

Vue:ref()

React:useRef()

7.4 Effect 副作用

Vue:无

React:useEffect() React 组件是比较"纯"的函数,它能保证输入和输出的一致性。与浏览器、API等外部系统等连接(如:网络请求、订阅事件、更新 DOM),要使用 useEffect() 钩子,而不是插入到组件的渲染中,这是跳出 React 的方式。

下面是 React 组件能够直接进行网络请求的两个位置:

ts 复制代码
// 在事件处理函数中
function onSubmit(e) {
	e.preventDefault();
	http.post('api/login', {...}).then(...).catch(...);
}
// 在 useEffect 中
useEffect(() => {
	const getData = async () => {
		fetch(url).then(...).catch(...)
	}
	getData();
},[])

7.5 Performance 性能优化

Vue:computed()

ts 复制代码
const count = ref(1);
const doubleCount = computed(() => count.value * 2);

React:useMemo(), useCallback()

ts 复制代码
// 1. useMemo()
// 接受一个函数和一个依赖项数组,它会在依赖项发生变化时重新计算函数的返回值,并将结果缓存起来。
import React, { useState, useMemo } from 'react';

const ExampleComponent = () => {
    const [count, setCount] = useState(0);

    // 使用 useMemo 缓存计算结果
    const doubleCount = useMemo(() => {
        return count * 2;
    }, [count]); // 仅在 count 发生变化时重新计算

    return (
        <div>
            <button onClick={() => setCount(count + 1)}>Increment Count</button>
            <p>Count: {count}</p>
            <p>double Count: {doubleCount}</p>
        </div>
    );
};

// 2. useCallback()
// 用于缓存回调函数,避免在每次渲染时创建新的回调函数。
import { useState, useCallback } from 'react';

const ExampleComponent = () => {
    const [count, setCount] = useState(0);

    // 使用 useCallback 缓存回调函数
    const increment = useCallback(() => {
        setCount(count + 1);
    }, [count]); // 仅在 count 发生变化时重新创建

    return (
        <div>
            <button onClick={increment}>Increment Count</button>
            <p>Count: {count}</p>
        </div>
    );
};

技术交流:

  • 公众号:见嘉 Being Dev
  • v:with_his_x
相关推荐
涔溪40 分钟前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss
龙猫蓝图2 小时前
vue el-date-picker 日期选择器禁用失效问题
前端·javascript·vue.js
fakaifa2 小时前
CRMEB Pro版v3.1源码全开源+PC端+Uniapp前端+搭建教程
前端·小程序·uni-app·php·源码下载
夜色呦2 小时前
掌握ECMAScript模块化:构建高效JavaScript应用
前端·javascript·ecmascript