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

如何从React的CompanySelector组件调用CompanyData组件的方法?

解决方案

因为你的两个组件是独立挂载到不同DOM节点的React根实例,所以无法直接调用对方的方法。这里给你两种简单可行的解决方案:


方案1:使用自定义事件(改动最小,适配现有代码结构)

通过浏览器自定义事件系统实现独立组件间通信,无需改动现有组件的挂载方式。

修改CompanyData.jsx

'use strict';

class CompanyData extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            error: null,
            isLoaded: false,
            info: null,
        };
        // 绑定方法上下文
        this.getCompanyData = this.getCompanyData.bind(this);
        this.handleCompanySelect = this.handleCompanySelect.bind(this);
    }

    componentDidMount() {
        // 监听自定义事件
        document.addEventListener('company-selected', this.handleCompanySelect);
    }

    componentWillUnmount() {
        // 组件卸载时移除监听,避免内存泄漏
        document.removeEventListener('company-selected', this.handleCompanySelect);
    }

    handleCompanySelect(event) {
        // 从事件中获取选中的公司ID,调用数据获取方法
        const companyId = event.detail;
        this.getCompanyData(companyId);
    }

    getCompanyData(id) {
        // 替换为实际API请求
        axios.get(`/api/companies/${id}`)
            .then(result => {
                this.setState({
                    isLoaded: true,
                    info: result.data,
                    error: null
                });
            })
            .catch(error => {
                this.setState({
                    error: error,
                    isLoaded: true
                });
                console.log(error);
            });
    }

    render() {
        if (this.state.error) {
            return <div>Error: {this.state.error.message}</div>
        }
        if (!this.state.isLoaded) {
            return <div>Select a company first!</div>
        } else {
            const info = this.state.info;
            return (
                <ul>
                    <li>{info.PreviousName}</li>
                    <li>{info.Industry}</li>
                    <li>{info.FoundedAt}</li>
                </ul>
            );
        }
    }

}

const eleInfo = document.getElementById('company-data');
const rootInfo = ReactDOM.createRoot(eleInfo);
rootInfo.render(<CompanyData />);

修改CompanySelector.jsx

仅需替换handleChange方法中的window.getCompanyData调用:

handleChange(evt) {
    const idx = evt.target.selectedIndex;
    const selectedCompanyId = this.state.companies[idx].CompanyID;
    this.setState({value: evt.target.value, index: idx});
    
    // 触发自定义事件,传递选中的公司ID
    const event = new CustomEvent('company-selected', { detail: selectedCompanyId });
    document.dispatchEvent(event);
}

方案2:统一到父组件管理状态(符合React单向数据流设计)

将两个组件整合到同一个React根下,通过父组件管理选中的公司ID,传递给CompanyData组件触发数据加载。

创建父组件(CompanyContainer.jsx)

'use strict';

class CompanyContainer extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            selectedCompanyId: null
        };
        this.handleCompanySelect = this.handleCompanySelect.bind(this);
    }

    handleCompanySelect(companyId) {
        this.setState({ selectedCompanyId: companyId });
    }

    render() {
        return (
            <div>
                <CompanySelector onCompanySelect={this.handleCompanySelect} />
                <CompanyData companyId={this.state.selectedCompanyId} />
            </div>
        );
    }
}

// 导入子组件(根据项目路径调整)
// import CompanySelector from './company-selector';
// import CompanyData from './company-data';

// 挂载父组件到DOM
const eleContainer = document.getElementById('company-container');
const rootContainer = ReactDOM.createRoot(eleContainer);
rootContainer.render(<CompanyContainer />);

修改CompanySelector.jsx

移除独立挂载代码,改为接收父组件回调:

'use strict';

class CompanySelector extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            error: null,
            isLoaded: false,
            companies: [],
            value: 0,
            index: 0,
        };

        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(evt) {
        const idx = evt.target.selectedIndex;
        const selectedCompanyId = this.state.companies[idx].CompanyID;
        this.setState({value: evt.target.value, index: idx});
        // 调用父组件传递的回调函数
        this.props.onCompanySelect(selectedCompanyId);
    }

    // 保留原componentDidMount和render方法...

}

// 移除原独立挂载代码,由父组件渲染
// const eleCompany = document.getElementById('company-selector');
// const rootCompany = ReactDOM.createRoot(eleCompany);
// rootCompany.render(<CompanySelector />);

export default CompanySelector;

修改CompanyData.jsx

根据props的companyId变化自动加载数据:

'use strict';

class CompanyData extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            error: null,
            isLoaded: false,
            info: null,
        };
        this.getCompanyData = this.getCompanyData.bind(this);
    }

    // 当props的companyId变化时,重新加载数据
    componentDidUpdate(prevProps) {
        if (this.props.companyId !== prevProps.companyId && this.props.companyId) {
            this.getCompanyData(this.props.companyId);
        }
    }

    getCompanyData(id) {
        axios.get(`/api/companies/${id}`)
            .then(result => {
                this.setState({
                    isLoaded: true,
                    info: result.data,
                    error: null
                });
            })
            .catch(error => {
                this.setState({
                    error: error,
                    isLoaded: true
                });
                console.log(error);
            });
    }

    render() {
        if (this.state.error) {
            return <div>Error: {this.state.error.message}</div>
        }
        if (!this.props.companyId) {
            return <div>Select a company first!</div>
        }
        if (!this.state.isLoaded) {
            return <div>Loading company data...</div>
        } else {
            const info = this.state.info;
            return (
                <ul>
                    <li>{info.PreviousName}</li>
                    <li>{info.Industry}</li>
                    <li>{info.FoundedAt}</li>
                </ul>
            );
        }
    }

}

// 移除原独立挂载代码,由父组件渲染
// const eleInfo = document.getElementById('company-data');
// const rootInfo = ReactDOM.createRoot(eleInfo);
// rootInfo.render(<CompanyData />);

export default CompanyData;

页面DOM调整

将原来的两个独立DOM节点替换为父节点:

<div id="company-container"></div>

注意事项

  • 方案1适合快速适配现有代码,方案2更符合React设计理念,推荐长期迭代使用。
  • 确保axios已全局引入或在组件中导入。
  • 方案2需根据项目结构调整组件的导出/导入路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 13:48:19