当前位置: 首页 > article >正文

React Refs 完整使用指南

React Refs 完整使用指南

1. Refs 基础用法

1.1 创建和访问 Refs

// 类组件中使用 createRef
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  componentDidMount() {
    // 访问 DOM 节点
    console.log(this.myRef.current);
  }

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

// 函数组件中使用 useRef
function MyFunctionComponent() {
  const myRef = useRef(null);

  useEffect(() => {
    // 访问 DOM 节点
    console.log(myRef.current);
  }, []);

  return <div ref={myRef}>Hello</div>;
}

1.2 回调 Refs

class CallbackRefComponent extends React.Component {
  setTextInputRef = (element) => {
    this.textInput = element;
  };

  focusTextInput = () => {
    // 直接使用原生 DOM API
    if (this.textInput) this.textInput.focus();
  };

  render() {
    return (
      <>
        <input type="text" ref={this.setTextInputRef} />
        <button onClick={this.focusTextInput}>
          Focus the text input
        </button>
      </>
    );
  }
}

2. Refs 常见用途

2.1 管理焦点

function FocusInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    // 组件挂载时自动聚焦
    inputRef.current.focus();
  }, []);

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={() => inputRef.current.focus()}>
        Focus Input
      </button>
    </div>
  );
}

2.2 文本选择

function TextSelection() {
  const textRef = useRef(null);

  const selectText = () => {
    if (textRef.current) {
      textRef.current.select();
    }
  };

  return (
    <div>
      <input
        ref={textRef}
        type="text"
        defaultValue="Click to select me"
      />
      <button onClick={selectText}>Select Text</button>
    </div>
  );
}

2.3 媒体控制

function VideoPlayer() {
  const videoRef = useRef(null);

  const handlePlay = () => {
    videoRef.current.play();
  };

  const handlePause = () => {
    videoRef.current.pause();
  };

  return (
    <div>
      <video ref={videoRef}>
        <source src="video.mp4" type="video/mp4" />
      </video>
      <button onClick={handlePlay}>Play</button>
      <button onClick={handlePause}>Pause</button>
    </div>
  );
}

3. Refs 转发

3.1 基本 Ref 转发

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="fancy-button">
    {props.children}
  </button>
));

// 使用转发的 ref
function Parent() {
  const buttonRef = useRef(null);

  useEffect(() => {
    console.log(buttonRef.current); // 访问 button DOM 节点
  }, []);

  return <FancyButton ref={buttonRef}>Click me!</FancyButton>;
}

3.2 高阶组件中的 Ref 转发

function withLogger(WrappedComponent) {
  class LoggerComponent extends React.Component {
    componentDidUpdate(prevProps) {
      console.log('Props updated', prevProps, this.props);
    }

    render() {
      const {forwardedRef, ...rest} = this.props;
      return <WrappedComponent ref={forwardedRef} {...rest} />;
    }
  }

  return React.forwardRef((props, ref) => {
    return <LoggerComponent {...props} forwardedRef={ref} />;
  });
}

// 使用高阶组件
const ButtonWithLogger = withLogger(FancyButton);

4. Refs 与函数组件

4.1 useImperativeHandle 使用

const FancyInput = React.forwardRef((props, ref) => {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    getValue: () => {
      return inputRef.current.value;
    },
    setValue: (value) => {
      inputRef.current.value = value;
    }
  }));

  return <input ref={inputRef} />;
});

// 使用自定义 ref 方法
function Parent() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
    inputRef.current.setValue('Hello!');
    console.log(inputRef.current.getValue());
  };

  return (
    <div>
      <FancyInput ref={inputRef} />
      <button onClick={handleClick}>Manipulate Input</button>
    </div>
  );
}

5. Refs 的高级用法

5.1 多个 Refs 管理

function MultipleRefs() {
  const refs = useRef({});

  const setRef = (id) => (element) => {
    refs.current[id] = element;
  };

  const focusRandom = () => {
    const keys = Object.keys(refs.current);
    const randomKey = keys[Math.floor(Math.random() * keys.length)];
    refs.current[randomKey]?.focus();
  };

  return (
    <div>
      <input ref={setRef('input1')} placeholder="Input 1" />
      <input ref={setRef('input2')} placeholder="Input 2" />
      <input ref={setRef('input3')} placeholder="Input 3" />
      <button onClick={focusRandom}>Focus Random Input</button>
    </div>
  );
}

5.2 条件性 Refs

function ConditionalRef() {
  const [showInput, setShowInput] = useState(true);
  const inputRef = useRef(null);

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

  return (
    <div>
      <button onClick={() => setShowInput(!showInput)}>
        Toggle Input
      </button>
      {showInput && <input ref={inputRef} />}
    </div>
  );
}

6. Refs 最佳实践

6.1 避免过度使用

// 不推荐
function BadExample() {
  const divRef = useRef(null);

  const updateContent = () => {
    // 不推荐直接操作 DOM
    divRef.current.innerHTML = 'Updated content';
  };

  return <div ref={divRef}>Content</div>;
}

// 推荐
function GoodExample() {
  const [content, setContent] = useState('Content');

  return <div>{content}</div>;
}

6.2 清理 Refs

function CleanupExample() {
  const timerRef = useRef(null);

  useEffect(() => {
    timerRef.current = setInterval(() => {
      console.log('Tick');
    }, 1000);

    // 清理定时器
    return () => {
      clearInterval(timerRef.current);
    };
  }, []);

  return <div>Timer Example</div>;
}

7. 总结

Refs 使用要���:

  1. 适用场景:

    • DOM 元素的直接操作
    • 媒体播放控制
    • 文本选择和焦点管理
    • 第三方 DOM 库的集成
  2. 注意事项:

    • 避免过度使用 Refs
    • 优先使用声明式编程
    • 及时清理 Refs 资源
    • 谨慎使用 Refs 操作 DOM
  3. 性能考虑:

    • Refs 更新不会触发重新渲染
    • 适当使用可以避免不必要的渲染
    • 大量 Refs 可能影响内存使用
  4. 开发建议:

    • 优先使用 React 的声明式 API
    • 只在必要时使用 Refs
    • 使用 TypeScript 增加类型安全
    • 保持代码的可维护性
      </rewritten_file>

http://www.kler.cn/a/449586.html

相关文章:

  • sqoop的参数有哪些?
  • 某集团GIF动态验证码识别
  • ubuntu 如何重装你的apt【apt-get报错: symbol lookup error/undefined symbol】
  • 解析在OceanBase创建分区的常见问题|OceanBase 用户问题精粹
  • 【机器学习与数据挖掘实战】案例06:基于Apriori算法的餐饮企业菜品关联分析
  • c# 实现一个简单的异常日志记录(异常迭代+分片+定时清理)+AOP Rougamo全局注入
  • ansible的流程控制
  • 重温设计模式--观察者模式
  • postman读取文件执行
  • 模型并行分布式训练 Megatron (3) ---模型并行实现
  • 数仓开发那些事(8)
  • starter-data-mongodb
  • PostCSS插件——postcss-pxtorem结合动态调整rem实现字体自适应
  • 开源低代码平台-Microi吾码 打印引擎使用
  • JavaScript从基础到进阶的155个问题
  • VSCode 配置远程连接免密登录 插件
  • 使用 C# 从 Web 下载文件
  • 数据分析实战—IMDB电影数据分析
  • 单元测试mock框架Mockito
  • 如果安装FreeSWICH?
  • 梳理你的思路(从OOP到架构设计)_设计模式Composite模式
  • 支付测试 流程
  • WPSJS:让 WPS 办公与 JavaScript 完美联动
  • lodash常用函数
  • Redis内存碎片详解
  • ue5 pcg(程序内容生成)真的简单方便,就5个节点