普通组件(例如 <div>)

所有的内置浏览器组件,例如 <div>,都支持一些常见的属性和事件。


参考

通用组件(例如 <div>

<div className="wrapper">一些内容</div>

参见下方更多示例

属性

这些特殊的 React 属性适用于所有内置组件:

  • children:React 节点(可以是元素、字符串、数字、portal,如 nullundefined 这样的空节点和布尔值,或其他 React 节点数组)。children 属性指定了组件内部的内容。当使用 JSX 时,通常会通过嵌套标签 <div><span /></div> 隐式地指定 children 属性。

  • dangerouslySetInnerHTML:一个形如 { __html: '<p>一些 HTML</p>' } 的对象,其中包含原始的 HTML 字符串。此属性将会覆盖 DOM 节点的 innerHTML 属性,并在内部显示传递的 HTML 内容。这个属性应该极度谨慎使用!如果内部的 HTML 不可信(例如它来源于用户数据),那么会有引入 XSS 漏洞的风险。阅读更多关于使用 dangerouslySetInnerHTML 的内容

  • ref:使用 useRef 或者 createRef 的 ref 对象,或者一个 ref 回调函数,再或者一个用于 传统 ref 的字符串。ref 将被填充为此节点的 DOM 元素。阅读更多关于使用 ref 操纵 DOM 的内容

  • suppressContentEditableWarning:布尔值。如果为 true 将会抑制 React 对同时具有 childcontentEditable={true} 属性的元素发出的警告(这两者通常不能同时使用)。如果你正在构建一个手动管理 contentEditable 内容的文本输入库,请使用此选项。

  • suppressHydrationWarning:布尔值。如果你使用 服务器渲染,通常会在服务器和客户端渲染不同内容时发出警告。在一些罕见的情况下(比如时间戳),很难或者不可能保证完全匹配。如果你设置 suppressHydrationWarningtrue,React 不会在元素属性和内容不匹配时发出警告。它只能在同级工作,并被作为脱围机制。阅读有关抑制 hydrate 错误的内容

  • style:CSS 样式对象,如 { fontWeight:'bold',margin:20 }。与 DOM style 属性类似,CSS 属性应该使用像 camelCase 这样的驼峰命名法,如应该使用 fontWeight 而不是 font-weight。你可以将字符串或数字作为值传递,类似 width: 100,React 会自动将值附加为 px(“像素”),除非它是一个 无单位的属性。我们建议仅在动态样式中使用 style,即事先不知道样式值。在其他情况下,使用普通的 CSS 类和 className 更有效。了解有关 classNamestyle 的更多信息

所有内置组件也支持这些标准的 DOM 属性:

你还可以将自定义属性作为 props 传递。例如 mycustomprop="someValue"。当与第三方库集成时,这可能很有用。但是自定义属性名称必须为小写,并且不能以 on 开头。该值将被转换为一个字符串。如果你传递 nullundefined,则自定义属性将被删除。

这些事件仅适用于 <form> 元素:

这些事件仅适用于 <dialog> 元素,与浏览器事件不同,React 中的事件会冒泡:

这些事件仅适用于 <details> 元素,与浏览器事件不同,React 中的事件会冒泡:

这些事件会触发在 <img><iframe><object><embed><link>SVG <image> 元素。与浏览器事件不同,React 中的事件会冒泡:

这些事件会触发在 <audio><video>。与浏览器事件不同,React 中的事件会冒泡:

注意

  • 你不能同时传递 childrendangerouslySetInnerHTML
  • 有些事件,如 onAbortonLoad,在浏览器中不冒泡,但是在 React 中仍然会冒泡。

ref 回调函数

useRef 返回的 ref 对象不同,可以将函数传递给 ref 属性。

<div ref={(node) => console.log(node)} />

查看使用 ref 回调函数的示例

<div> DOM 节点被添加到屏幕上时,React 将使用该节点作为参数调用 ref 回调函数。

当传递不同的ref回调时,React 也会调用 ref 回调。在上面的示例中,(node) => { ... } 在每次渲染时都是一个不同的函数。当组件重新渲染时,先前的函数将被调用并传递 null 作为参数,并且下一个函数将被调用并传递对应 DOM 节点作为参数。

参数

  • node:DOM 节点或 null。当回调函数被附加在 ref 属性后,触发回调时,该参数为对应的 DOM 节点。当 ref 被分离时值为 null。除非在每次渲染时都传递相同的函数引用作为 ref 回调,否则该回调将在组件的每次重新渲染期间被暂时分离和重新连接。

Canary

返回值

  • optional cleanup function: When the ref is detached, React will call the cleanup function. If a function is not returned by the ref callback, React will call the callback again with null as the argument when the ref gets detached.

<div ref={(node) => {
console.log(node);

return () => {
console.log('Clean up', node)
}
}}>

Caveats

  • When Strict Mode is on, React will run one extra development-only setup+cleanup cycle before the first real setup. This is a stress-test that ensures that your cleanup logic “mirrors” your setup logic and that it stops or undoes whatever the setup is doing. If this causes a problem, implement the cleanup function.
  • When you pass a different ref callback, React will call the previous callback’s cleanup function if provided. If not cleanup function is defined, the ref callback will be called with null as the argument. The next function will be called with the DOM node.

React 事件对象

你的事件处理程序将接收到一个 React 事件对象。它有时也被称为“合成事件”(synthetic event)。

<button onClick={e => {
console.log(e); // React 事件对象
}} />

它符合与底层 DOM 事件相同的标准,但修复了一些浏览器不一致性。

一些 React 事件不能直接映射到浏览器的原生事件。例如,onMouseLeave 中的 e.nativeEvent 将指向 mouseout 事件。具体的映射关系不是公共 API 的一部分,可能会在未来发生变化。如果处于某些原因需要浏览器的原生事件,请从 e.nativeEvent 中读取它。

属性

React 事件对象实现了一些标准的 Event 属性:

  • bubbles:布尔值,返回事件是否会在 DOM 中冒泡传播。
  • cancelable:布尔值,返回事件是否可以被取消。
  • currentTarget:DOM 节点,返回当前处理程序所附加到的节点在 React 树中的位置。
  • defaultPrevented:布尔值,返回是否调用了 preventDefault
  • eventPhase:数字,返回事件当前所处的阶段。
  • isTrusted:布尔值,返回事件是否由用户发起。
  • target:DOM 节点,返回事件发生的节点(可能是远程子节点)。
  • timeStamp:数字,返回事件发生的时间。

此外,React 事件对象额外提供了以下属性:

  • nativeEvent:DOM Event 对象,即浏览器的原生事件对象。

方法

React 事件对象实现了一些标准的 Event 方法:

此外,React 事件对象提供了以下方法:

  • isDefaultPrevented():返回布尔值,表示是否调用了 preventDefault 方法。
  • isPropagationStopped():返回一个布尔值,表示是否调用了 stopPropagation 方法。
  • persist():不适用于 React DOM。在 React Native 中,调用此函数以读取事件后的属性。
  • isPersistent():不适用于 React DOM。在 React Native 中,返回是否已调用 persist

注意

  • currentTargeteventPhasetargettype 的值反映了 React 代码所期望的值。实际上 React 在节点附加事件处理程序,但这不会体现在 React 事件对象中。例如,e.currentTarget 可能与原生 e.nativeEvent.currentTarget 不同。对于 polyfill 事件,e.type(React 事件类型)可能与 e.nativeEvent.type(原生事件类型)不同。

AnimationsEvent 处理函数

一个用于 CSS 动画 事件的事件处理程序类型。

<div
onAnimationStart={e => console.log('onAnimationStart')}
onAnimationIteration={e => console.log('onAnimationIteration')}
onAnimationEnd={e => console.log('onAnimationEnd')}
/>

参数


ClipboardEvent 处理函数

一个用于 Clipboard API 事件的处理程序类型。

<input
onCopy={e => console.log('onCopy')}
onCut={e => console.log('onCut')}
onPaste={e => console.log('onPaste')}
/>

参数


CompositionEvent 处理函数

一个用于 输入法编辑器(IME) 的事件处理程序类型。

<input
onCompositionStart={e => console.log('onCompositionStart')}
onCompositionUpdate={e => console.log('onCompositionUpdate')}
onCompositionEnd={e => console.log('onCompositionEnd')}
/>

参数


DragEvent 事件处理函数

HTML Drag 和 Drop API 事件的事件处理程序类型。

<>
<div
draggable={true}
onDragStart={e => console.log('onDragStart')}
onDragEnd={e => console.log('onDragEnd')}
>
拖拽源
</div>

<div
onDragEnter={e => console.log('onDragEnter')}
onDragLeave={e => console.log('onDragLeave')}
onDragOver={e => { e.preventDefault(); console.log('onDragOver'); }}
onDrop={e => console.log('onDrop')}
>
拖拽目标
</div>
</>

参数


FocusEvent 处理函数

一个用于焦点事件的事件处理程序类型。

<input
onFocus={e => console.log('onFocus')}
onBlur={e => console.log('onBlur')}
/>

看一个例子

参数


Event 处理函数

一个通用事件的事件处理程序类型。

参数


InputEvent 处理函数

一个用于 onBeforeInput 事件的事件处理程序类型。

<input onBeforeInput={e => console.log('onBeforeInput')} />

属性


KeyboardEvent 处理函数

一个用于键盘事件的事件处理程序类型。

<input
onKeyDown={e => console.log('onKeyDown')}
onKeyUp={e => console.log('onKeyUp')}
/>

看一个例子

参数


MouseEvent 处理函数

一个用于鼠标事件的事件处理程序类型。

<div
onClick={e => console.log('onClick')}
onMouseEnter={e => console.log('onMouseEnter')}
onMouseOver={e => console.log('onMouseOver')}
onMouseDown={e => console.log('onMouseDown')}
onMouseUp={e => console.log('onMouseUp')}
onMouseLeave={e => console.log('onMouseLeave')}
/>

看一个例子

参数

它还包括继承的 UIEvent 属性:


PointerEvent 处理函数

一个 指针事件 的事件处理程序类型。

<div
onPointerEnter={e => console.log('onPointerEnter')}
onPointerMove={e => console.log('onPointerMove')}
onPointerDown={e => console.log('onPointerDown')}
onPointerUp={e => console.log('onPointerUp')}
onPointerLeave={e => console.log('onPointerLeave')}
/>

看一个例子

参数

它还包括继承的 UIEvent 属性:


TouchEvent 处理函数

一个用于 触摸事件 的事件处理程序类型。

<div
onTouchStart={e => console.log('onTouchStart')}
onTouchMove={e => console.log('onTouchMove')}
onTouchEnd={e => console.log('onTouchEnd')}
onTouchCancel={e => console.log('onTouchCancel')}
/>

参数

它还包括继承的 UIEvent 属性:


TransitionEvent 处理函数

一个用于 CSS 过渡的事件处理程序类型。

<div
onTransitionEnd={e => console.log('onTransitionEnd')}
/>

参数


UIEvent 处理函数

一个通用 UI 事件的事件处理程序类型。

<div
onScroll={e => console.log('onScroll')}
/>

参数


WheelEvent 处理函数

一个用于 onWheel 事件的事件处理程序类型。

<div
onWheel={e => console.log('onWheel')}
/>

参数

它还包括继承的 MouseEvent 属性:

它还包括继承的 UIEvent 属性:


用法

应用 CSS 样式

在 React 中,你可以使用 className 指定 CSS 类。它的工作方式类似于 HTML 中的 class 属性:

<img className="avatar" />

然后你在单独的 CSS 文件中编写它的 CSS 规则:

/* 在你的 CSS 文件中 */
.avatar {
border-radius: 50%;
}

在最简单的情况下,你可以将 <link> 标签添加到 HTML 中。如果你使用构建工具或框架,请查阅其文档以了解如何将 CSS 文件添加到项目中。React 不规定如何添加 CSS 文件。

有时,样式值取决于数据。使用 style 属性动态传递一些样式:

<img
className="avatar"
style={{
width: user.imageSize,
height: user.imageSize
}}
/>

在上述例子中,style={{}} 不是一个特殊的语法,而是将 style={ } JSX 花括号 放在一个普通 {} 中。我们建议只在样式依赖于 JavaScript 变量时使用 style 属性。

export default function Avatar({ user }) {
  return (
    <img
      src={user.imageUrl}
      alt={'Photo of ' + user.name}
      className="avatar"
      style={{
        width: user.imageSize,
        height: user.imageSize
      }}
    />
  );
}

深入探讨

如何有条件地应用多个 CSS 类?

要有条件地应用 CSS 类,你需要使用 JavaScript 自己生成 className 字符串。

例如,className={'row ' + (isSelected ? 'selected':'')} 将会生成 className="row" 还是 className="row selected" 取决于 isSelected 是否为 true

使用像 classnames 这样的小助手库以维持代码可读性:

import cn from 'classnames';

function Row({ isSelected }) {
return (
<div className={cn('row', isSelected && 'selected')}>
...
</div>
);
}

如果你有多个条件类,则特别方便:

import cn from 'classnames';

function Row({ isSelected, size }) {
return (
<div className={cn('row', {
selected: isSelected,
large: size === 'large',
small: size === 'small',
})}>
...
</div>
);
}

使用 ref 操作 DOM 节点

有时需要获取与 JSX 标签相关联的浏览器 DOM 节点。举个例子,当你希望在点击按钮时聚焦于一个 <input>,你需要在浏览器的<input> DOM 节点上调用 focus() 方法。

要获取标签的浏览器 DOM 节点,请 声明一个 ref 并将其作为一个 ref 属性传递给标签:

import { useRef } from 'react';

export default function Form() {
const inputRef = useRef(null);
// ...
return (
<input ref={inputRef} />
// ...

在渲染到屏幕后,React 会将 DOM 节点放入 inputRef.current 中。

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

阅读更多关于 使用 ref 操纵 DOM 的内容并 查看更多示例

对于更高级的用例,ref 属性还可以接受 回调函数


危险地设置内部 HTML

你可以像这样将原始的 HTML 字符串传递给元素:

const markup = { __html:'<p>some raw html</p>' };
return <div dangerouslySetInnerHTML={markup} />;

这很危险。与底层的 DOM innerHTML 属性一样,你必须极度谨慎!除非标记语言来自完全可信的来源,否则通过这种方式引入 XSS 是容易被攻击的

例如,如果你使用将 Markdown 转换为 HTML 的 Markdown 库,你得相信它的解析器没有漏洞,用户只能看到自己的输入,你可以像这样显示生成的 HTML:

import { Remarkable } from 'remarkable';

const md = new Remarkable();

function renderMarkdownToHTML(markdown) {
  // 这里安全的原因是输出的 HTML 代码
  // 仅显示给同一用户,
  // 并且你信任此 Markdown 解析器没有漏洞。
  const renderedHTML = md.render(markdown);
  return {__html: renderedHTML};
}

export default function MarkdownPreview({ markdown }) {
  const markup = renderMarkdownToHTML(markdown);
  return <div dangerouslySetInnerHTML={markup} />;
}

{__html} 对象应尽可能在接近生成 HTML 的位置创建,就像上面的示例在 renderMarkdownToHTML 函数中所做的那样。这确保了代码中使用的所有原始 HTML 都明确标记为这样,并且只有你期望包含 HTML 的变量被传递给 dangerouslySetInnerHTML。不建议像 <div dangerouslySetInnerHTML={{__html: markup}} /> 这样内联创建对象。

要了解为什么渲染任意 HTML 是危险的,请将上面的代码替换为此代码:

const post = {
// 想象这个内容被存储在数据库中
content: `<img src="" onerror='alert("你被入侵了")'>`
};

export default function MarkdownPreview() {
// 🔴 安全漏洞:将不受信任的输入传递给 dangerouslySetInnerHTML
const markup = { __html: post.content };
return <div dangerouslySetInnerHTML={markup} />;
}

HTML 中嵌入的代码将会运行。黑客可以利用这个安全漏洞窃取用户信息或代表他们执行操作。 只有在使用受信任和经过消毒的数据时才能使用 dangerouslySetInnerHTML


处理鼠标事件

这个例子展示了一些常见的 鼠标事件 以及它们触发的时机。

export default function MouseExample() {
  return (
    <div
      onMouseEnter={e => console.log('onMouseEnter (parent)')}
      onMouseLeave={e => console.log('onMouseLeave (parent)')}
    >
      <button
        onClick={e => console.log('onClick (first button)')}
        onMouseDown={e => console.log('onMouseDown (first button)')}
        onMouseEnter={e => console.log('onMouseEnter (first button)')}
        onMouseLeave={e => console.log('onMouseLeave (first button)')}
        onMouseOver={e => console.log('onMouseOver (first button)')}
        onMouseUp={e => console.log('onMouseUp (first button)')}
      >
        First button
      </button>
      <button
        onClick={e => console.log('onClick (second button)')}
        onMouseDown={e => console.log('onMouseDown (second button)')}
        onMouseEnter={e => console.log('onMouseEnter (second button)')}
        onMouseLeave={e => console.log('onMouseLeave (second button)')}
        onMouseOver={e => console.log('onMouseOver (second button)')}
        onMouseUp={e => console.log('onMouseUp (second button)')}
      >
        Second button
      </button>
    </div>
  );
}


处理指针事件

这个例子展示了一些常见的 指针事件 以及它们触发的时机。

export default function PointerExample() {
  return (
    <div
      onPointerEnter={e => console.log('onPointerEnter (parent)')}
      onPointerLeave={e => console.log('onPointerLeave (parent)')}
      style={{ padding: 20, backgroundColor: '#ddd' }}
    >
      <div
        onPointerDown={e => console.log('onPointerDown (first child)')}
        onPointerEnter={e => console.log('onPointerEnter (first child)')}
        onPointerLeave={e => console.log('onPointerLeave (first child)')}
        onPointerMove={e => console.log('onPointerMove (first child)')}
        onPointerUp={e => console.log('onPointerUp (first child)')}
        style={{ padding: 20, backgroundColor: 'lightyellow' }}
      >
        First child
      </div>
      <div
        onPointerDown={e => console.log('onPointerDown (second child)')}
        onPointerEnter={e => console.log('onPointerEnter (second child)')}
        onPointerLeave={e => console.log('onPointerLeave (second child)')}
        onPointerMove={e => console.log('onPointerMove (second child)')}
        onPointerUp={e => console.log('onPointerUp (second child)')}
        style={{ padding: 20, backgroundColor: 'lightblue' }}
      >
        Second child
      </div>
    </div>
  );
}


处理焦点事件

在 React 中,焦点事件 冒泡。你可以使用 currentTargetrelatedTarget 来区分焦点或模糊事件是否起源于父元素之外。该示例展示了如何检测子元素的聚焦、父级元素的聚焦,以及如何检测整个子树的聚焦进入或离开。

export default function FocusExample() {
  return (
    <div
      tabIndex={1}
      onFocus={(e) => {
        if (e.currentTarget === e.target) {
          console.log('focused parent');
        } else {
          console.log('focused child', e.target.name);
        }
        if (!e.currentTarget.contains(e.relatedTarget)) {
          // 在子元素之间切换焦点时不会触发
          console.log('focus entered parent');
        }
      }}
      onBlur={(e) => {
        if (e.currentTarget === e.target) {
          console.log('unfocused parent');
        } else {
          console.log('unfocused child', e.target.name);
        }
        if (!e.currentTarget.contains(e.relatedTarget)) {
          // 在子元素之间切换焦点时不会触发
          console.log('focus left parent');
        }
      }}
    >
      <label>
        First name:
        <input name="firstName" />
      </label>
      <label>
        Last name:
        <input name="lastName" />
      </label>
    </div>
  );
}


处理键盘事件

这个例子展示了一些常见的 键盘事件 以及它们触发的时机。

export default function KeyboardExample() {
  return (
    <label>
      First name:
      <input
        name="firstName"
        onKeyDown={e => console.log('onKeyDown:', e.key, e.code)}
        onKeyUp={e => console.log('onKeyUp:', e.key, e.code)}
      />
    </label>
  );
}