React 高级指引

# 无障碍表单

# 标记

所有的 HTML 表单控制,例如 <input><textarea> ,都需要被标注来实现无障碍辅助功能。我们需要提供屏幕朗读器以解释性标注。

<label htmlFor="namedInput">Name:</label>
<input id="namedInput" type="text" name="name"/>

# Refs 转发

Ref 转发是一项将 ref 自动地通过组件传递到其一子组件的技巧。对于大多数应用中的组件来说,这通常不是必需的。但其对某些组件,尤其是可重用的组件库是很有用的。最常见的案例如下所述。

简单来说 — 进行 DOM 操作 – 官方建议不要优先使用 Ref,而考虑使用 state

# react 提供 3 种方式进行 ref 使用

  1. 字符串的方式
  2. 回调函数 (推荐)
    • 就是在 dom 节点上或者组件上挂载函数,函数的形参 试 dom 节点,达到的效果和字符串是一样的,都是获取值的引用
  3. React.createRef () — react16.3 新提供的方式。

# 字符串的方式

class MyComponent extends React.Component {
  hanle(){
    console.log(this.refs.demoref);
  }
  render(){
    return(
      <div>
      <input type="text" 
      ref = 'demoref'
      placeholder='请输入...'/> 
      <button onClick = {()=> this.hanle()}>点击</button>
		</div>
		)
	}
}

# 回调函数

class MyComponent extends React.Component {
      hanle() {
        console.log(this.demoref);
      }
      render() {
        return (
          <div>
            <input
              type="text"
              ref={(input) => (this.demoref = input)}
              placeholder="请输入..."
            />

            <button onClick={() => this.hanle()}>点击</button>
          </div>
        );
      }
    }

    ReactDOM.render(<MyComponent />, document.getElementById("app"));

# React.createRef

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  componentDidMount() {
    this.myRef.current.style.border = '1px solid red';
  }

  render() {
    return <div ref={this.myRef}>
      <h1>123123</h1>
    </div>;
  }
}

ReactDOM.render(<MyComponent />, document.getElementById("app"));

# Fragments

React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。

有时,语义化的 HTML 会被破坏。比如当在 JSX 中使用 <div> 元素来实现 React 代码功能的时候,又或是在使用列表( <ol><ul><dl> )和 HTML <table> 时。 在这种情况下,我们应该使用 React Fragments 来组合各个组件

class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}

# 短语法

你可以使用一种新的,且更简短的语法来声明 Fragments。它看起来像空标签:

class Columns extends React.Component {
  render() {
    return (
      <>
        <td>Hello</td>
        <td>World</td>
      </>
    );
  }
}

# 带 key 的 Fragments

使用显式 <React.Fragment> 语法声明的片段可能具有 key。一个使用场景是将一个集合映射到一个 Fragments 数组 - 举个例子,创建一个描述列表:

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        // 没有`key`,React 会发出一个关键警告
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}

key 是唯一可以传递给 Fragment 的属性。未来我们可能会添加对其他属性的支持,例如事件。

# Refs and the DOM

Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素

在典型的 React 数据流中,props 是父组件与子组件交互的唯一方式。要修改一个子组件,你需要使用新的 props 来重新渲染它。但是,在某些情况下,你需要在典型数据流之外强制修改子组件。被修改的子组件可能是一个 React 组件的实例,也可能是一个 DOM 元素。对于这两种情况,React 都提供了解决办法。

# 何时使用 Refs

下面是几个适合使用 refs 的情况:

  • 管理焦点,文本选择或媒体播放。
  • 触发强制动画。
  • 集成第三方 DOM 库。

避免使用 refs 来做任何可以通过声明式实现来完成的事情。

举个例子,避免在 Dialog 组件里暴露 open()close() 方法,最好传递 isOpen 属性。

# 勿过度使用 Refs

你可能首先会想到使用 refs 在你的 app 中 “让事情发生”。如果是这种情况,请花一点时间,认真再考虑一下 state 属性应该被安排在哪个组件层中。通常你会想明白,让更高的组件层级拥有这个 state,是更恰当的。查看 状态提升 以获取更多有关示例。

# 创建 Refs

React.createRef

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

# 为 DOM 元素添加 ref

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  componentDidMount() {
    this.myRef.current.style.border = '1px solid red';
  }

  render() {
    return <div ref={this.myRef}>
      <h1>123123</h1>
    </div>;
  }
}

ReactDOM.render(<MyComponent />, document.getElementById("app"));

# 为 class 组件添加 Ref

class AutoFocusTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  componentDidMount() {
    this.textInput.current.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput ref={this.textInput} />
    );
  }
}

# Refs 与函数组件

默认情况下,你不能在函数组件上使用 ref 属性,因为它们没有实例

如果要在函数组件中使用 ref ,你可以使用 forwardRef (可与 useImperativeHandle 结合使用),或者可以将该组件转化为 class 组件。

不管怎样,你可以在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件:

function CustomTextInput(props) {
  // 这里必须声明 textInput,这样 ref 才可以引用它
  const textInput = useRef(null);

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

  return (
    <div>
      <input
        type="text"
        ref={textInput} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2015-2021 zhou chen
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信