You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中渲染后调用MaterializeCSS装饰DOM节点的正确方式

在React中正确初始化MaterializeCSS组件的方案

我完全懂你的困扰——在React里整合Materialize这类依赖DOM操作的UI库,确实容易陷入“用jQuery思路写React”的误区。你当前靠ID+componentDidMount()的方法虽然能跑,但确实不是最符合React范式的实现,这里有几个更优雅且可靠的方案:

一、使用React Refs(官方推荐)

Refs是React专门用来访问DOM元素或组件实例的方式,相比document.querySelector,它不需要依赖全局ID,不会产生命名冲突,而且能直接获取到组件渲染后的真实DOM节点,完全符合React的组件化逻辑。

1. 类组件场景

import React, { Component, createRef } from 'react';

class CustomSelect extends Component {
  // 创建Ref关联DOM节点
  selectRef = createRef();

  componentDidMount() {
    // 确保DOM节点已挂载完成
    if (this.selectRef.current) {
      // 初始化Materialize Select组件
      M.FormSelect.init(this.selectRef.current, {});
    }
  }

  componentDidUpdate(prevProps) {
    // 当选项数据变化时,需要重新初始化(Materialize不会自动感知DOM更新)
    if (prevProps.options !== this.props.options) {
      // 先销毁旧实例,避免内存泄漏
      const instance = M.FormSelect.getInstance(this.selectRef.current);
      if (instance) instance.destroy();
      // 重新初始化
      M.FormSelect.init(this.selectRef.current, {});
    }
  }

  componentWillUnmount() {
    // 组件卸载前清理Materialize实例
    const instance = M.FormSelect.getInstance(this.selectRef.current);
    if (instance) instance.destroy();
  }

  render() {
    const { options } = this.props;
    return (
      <select ref={this.selectRef}>
        {options.map(opt => (
          <option key={opt.value} value={opt.value}>{opt.label}</option>
        ))}
      </select>
    );
  }
}

2. 函数组件场景

用useRef和useEffect组合实现,逻辑和类组件一致:

import React, { useRef, useEffect } from 'react';

const CustomSelect = ({ options }) => {
  const selectRef = useRef(null);

  useEffect(() => {
    let selectInstance;
    // 初始化组件
    if (selectRef.current) {
      selectInstance = M.FormSelect.init(selectRef.current, {});
    }

    // 清理函数:组件卸载或依赖变化时销毁实例
    return () => {
      if (selectInstance) {
        selectInstance.destroy();
      }
    };
  }, [options]); // 当options变化时重新执行初始化

  return (
    <select ref={selectRef}>
      {options.map(opt => (
        <option key={opt.value} value={opt.value}>{opt.label}</option>
      ))}
    </select>
  );
};

二、封装可复用的自定义Hook(函数组件进阶)

如果你的项目中有多个需要初始化的Materialize组件,可以把初始化逻辑抽成自定义Hook,实现代码复用:

import { useRef, useEffect } from 'react';

// 自定义Hook:封装Materialize Select的初始化逻辑
const useMaterializeSelect = (config = {}) => {
  const elementRef = useRef(null);

  useEffect(() => {
    let instance;
    if (elementRef.current) {
      instance = M.FormSelect.init(elementRef.current, config);
    }

    return () => {
      if (instance) instance.destroy();
    };
  }, [config]);

  return elementRef;
};

// 使用Hook的组件
const CustomSelect = ({ options }) => {
  const selectRef = useMaterializeSelect();

  return (
    <select ref={selectRef}>
      {options.map(opt => (
        <option key={opt.value} value={opt.value}>{opt.label}</option>
      ))}
    </select>
  );
};

关键注意事项

  • 清理实例:一定要在组件卸载或重新初始化前调用destroy()方法,避免内存泄漏和DOM残留问题。
  • 响应props变化:Materialize不会自动感知DOM内容的更新(比如选项列表变化),所以需要在componentDidUpdate或useEffect的依赖数组中加入相关props,触发重新初始化。
  • 避免全局ID冲突:用Ref替代ID查询,能彻底避免多个组件ID重复的问题,尤其是在组件复用场景下。

对比你的临时方案,Ref的方式更贴合React的设计思想,代码更健壮,也更易于维护和复用。

内容的提问来源于stack exchange,提问作者Jeffrey04

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:50:36