赶集回来!React 组件大集合上映🤩

929 阅读5分钟

如果你有Vue 基础,可以对比学习。如果你只是React 新手,那这篇“组件大集合” 很适合你

从组件通信到表单管理,再到异步渲染,React提供了强大的工具和灵活的机制,帮助开发者高效地构建交互式应用。无论是父子组件之间的数据传递,还是通过createPortal实现的全局组件渲染,亦或是Suspense带来的优雅异步加载体验,React都展现出了其独特的优势。

下面多采用TS 方式,可以当成TS规范了属性样式去学习。

一、组件通信:父子组件的“对话”

1. 父组件向子组件传递props

父组件就像一个“家长”,把一些信息(props)传递给子组件。子组件通过函数的参数接收这些props

props是一个对象,里面可以包含各种数据,比如字符串、数字、数组、函数等。举个例子:

// 父组件
const ParentComponent = () => {
  const name = "小微";
  return <ChildComponent name={name} />;
};

// 子组件
const ChildComponent: React.FC<{ name: string }> = ({ name }) => {
  return <div>Hello, {name}!</div>;
};

在上面的例子中,ParentComponentname这个props传递给ChildComponentChildComponent通过解构的方式接收name,并在页面上显示出来。

(是不是很像Vue 父传子)

2. 子组件不能修改props

React规定了单向数据流,子组件不能直接修改父组件传递过来的props。这是因为如果子组件可以随意修改props,就会导致数据流向混乱,难以追踪数据的变化。

React的源码中会使用Object.freeze来冻结props,防止子组件修改它。Object.freeze是一个非常强大的方法,它可以让一个对象“冻结”,不能添加新属性、删除现有属性,也不能修改属性的值、可枚举性、可配置性等。

这样保证性能更好,副作用更少——确定子组件不能修改props 信息,也减少不必要的渲染。

3. 父组件通过回调函数接收子组件的“消息”

虽然子组件不能直接修改props,但它可以通过回调函数把一些信息传递回父组件。父组件把一个函数作为props传递给子组件,子组件在需要的时候调用这个函数,就像是给父组件发了一个“消息”。比如:

// 父组件
const ParentComponent = () => {
  const handleChildMessage = (message: string) => {
    console.log("Child says:", message);
  };
  return <ChildComponent onMessage={handleChildMessage} />;
};

// 子组件
const ChildComponent: React.FC<{ onMessage: (message: string) => void }> = ({ onMessage }) => {
  return <button onClick={() => onMessage("Hello from child!")}>Send Message</button>;
};

在这个例子中,ChildComponent有一个按钮,点击按钮时会调用onMessage函数,并传递一个消息给ParentComponent。(Vue 里面就是使用emit事件完成一样功能)

二、受控组件与非受控组件:表单元素的管理方式

1. 受控组件

受控组件是React管理表单元素的一种方式。它适用于大部分表单元素,如inputtextareaselect等(除了input type="file")。

在受控组件中,表单元素的值是由React的state来控制的。这意味着,表单元素的值会随着state的变化而变化,而用户对表单元素的输入也会触发state的更新。例如:

import React, { useState } from 'react';

const ControlledForm = () => {
  const [inputValue, setInputValue] = useState('');

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInputValue(e.target.value);
  };

  return (
    <input type="text" value={inputValue} onChange={handleChange} />
  );
};

在这个例子中,input的值是由inputValue这个state来控制的,用户输入的内容会通过handleChange函数更新inputValue,从而实现受控。

2. 非受控组件

非受控组件则是表单元素的值由DOM自己管理,而不是React的state。我们可以通过 useRef 来获取表单元素的值。这种方式在处理input type="file"时比较常用,因为文件输入的值很难通过state来控制。例如:

import React, { useRef } from 'react';

const UncontrolledForm = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleSubmit = () => {
    console.log(inputRef.current?.value);
  };

  return (
    <>
      <input type="text" ref={inputRef} />
      <button onClick={handleSubmit}>Submit</button>
    </>
  );
};

在这个例子中,我们通过useRef获取了input的引用,然后在提交的时候通过inputRef.current.value来获取输入的值。

三、createPortal:把组件“传送”到任意位置

createPortal是React提供的一个很有用的功能,它有点像Vue里的teleport。你可以用它把一个组件渲染到DOM的任意位置,而不是局限于父组件的DOM结构中。这在处理一些全局组件(如弹窗、下拉框、全局提示等)时非常方便。

import React from 'react';
import ReactDOM from 'react-dom';

const Modal = () => {
  return ReactDOM.createPortal(
    <div className="modal">
      <p>这是一个模态框</p>
    </div>,
    document.body
  );
};

在这个例子中,Modal组件通过createPortal被渲染到了document.body中,而不是它原本的位置。这样就可以让模态框脱离父组件的样式限制,更好地实现全局覆盖的效果。

四、Suspense:异步渲染的“魔法”

在React 18和React 19中,Suspense是一个非常重要的特性,它可以让组件异步加载,提升应用的性能和用户体验。

1. 使用lazySuspense异步加载组件

你可以用React.lazy来定义一个异步组件,然后用Suspense来包裹它。Suspensefallback属性可以指定一个占位组件,在异步组件加载的过程中显示。例如:

import React, { Suspense, lazy } from 'react';

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

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

在这个例子中,AsyncComponent是一个异步加载的组件,当它还没有加载完成的时候,会显示Loading...这个占位组件。

2. 骨架屏提升用户体验

骨架屏是一种很常见的占位组件,它可以让用户在数据加载的过程中看到一个类似真实内容的“骨架”,而不是一个简单的加载动画。通过Suspense和骨架屏组件,你可以实现一个非常流畅的加载效果。例如:

import React, { Suspense, lazy } from 'react';

const Card = lazy(() => import('./components/Card'));
const Skeleton = () => <div className="skeleton">Loading...</div>;

const App = () => {
  return (
    <Suspense fallback={<Skeleton />}>
      <Card />
    </Suspense>
  );
};

在这个例子中,Card组件是异步加载的,当它还在加载的时候,会显示一个骨架屏组件Skeleton。一旦Card加载完成,骨架屏就会被替换掉,显示真实的内容。

总结

React组件的使用涉及到很多细节,包括组件通信、表单管理、组件渲染位置以及异步加载等。通过合理地使用这些特性,你可以构建出高性能、用户体验良好的React应用。 希望这篇文章能帮助你更好地理解和使用React组件!😎

参考文档: React docs