【问题标题】:How to call a method on a React component from another component如何从另一个组件调用 React 组件上的方法
【发布时间】:2022-08-20 01:20:20
【问题描述】:

我有一个用 Laravel 和 jQuery 编写的大型内部 Web 应用程序,并且正在尝试将可重用的 React 组件集成到其中(我是 React 的新手)。

我有一个 CompanySelector 组件正在工作 - 一个使用 axios 从数据库中获取数据并填充列表的选择元素。 当前,当用户从列表中选择一个项目时,它会调用window.getCompanyData(this.state.companies[idx].CompanyID),这是一个加载数据的jQuery 函数——可以工作。 我想用另一个 React 组件替换它,该组件将在选择公司时处理它自己的数据的加载。

公司选择器.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;
        this.setState({value: evt.target.value, index: idx});
        window.getCompanyData(this.state.companies[idx].CompanyID);
    }

    componentDidMount() {
        axios
            .get(\'/api/companies\')
            .then((result) => {
                this.setState({
                    isLoaded: true,
                    index: 0,
                    companies: result.data.companies.data,
                    value: 0,
                });
            })
            .catch((error) => {
                console.log(error);
            });
    }

    render() {
        if (this.state.error) {
            return <div>Error: {this.state.error.message}</div>
        }
        if (!this.state.isLoaded) {
            return <div>Loading ...</div>
        } else {
            return (
                <select className=\"form-select\" value={this.state.value} onChange={this.handleChange}>
                    <option value=\"0\" defaultValue disabled>Select Client</option>
                    {this.state.companies.map((item, idx) => (
                        <option key={idx} value={item.CompanyID}>{item.FullCompanyName}</option>
                    ))}
                </select>
            );
        }
    }

}

const eleCompany = document.getElementById(\'company-selector\');
const rootCompany = ReactDOM.createRoot(eleCompany);
rootCompany.render(<CompanySelector />);

到目前为止,我的公司数据组件:

\'use strict\';

class CompanyData extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            error: null,
            isLoaded: false,
            info: null,
        };
    }

    getCompanyData(id) {
        alert(\'fetch data\');
    }

    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 {
            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 组件调用 CompanyData 组件的 getCompanyData 函数?

我已经在网上进行了广泛的搜索,但这些示例要么似乎不适合我的用例,要么完全超出我的想象!

    标签: jquery reactjs


    【解决方案1】:

    如果它们是独立的并且您想重用该逻辑,请创建将该功能作为道具注入的 HOC。

    如果其中一个是 Parent 而另一个是 Child,则将该函数作为 prop 从 Parent 传递给 Child

    如果他们是兄弟姐妹,您可以将函数作为他们共同父母的道具传递

    HOC实施:

    const withCompanyData = (Comp) => {
      return class WrapperComponent extends React.Component {
        state = {
          info: null
        }
        getCompanyData = () => {
          // do fetch here and update state
          // and update state
        }
        render() {
          return <Comp getCompanyData={this.getCompanyData} companyState={this.state} />
        }
      }
    }
    

    并像这样使用它:

    const CompanyDataComponent = withCompanyData(CompanyData)
    const CompanySelectorComponent = withCompanyData(CompanySelector)
    

    现在,当您致电&lt;CompanyDataComponent /&gt; 时,在您的CompanyData 中,您可以通过以下方式访问getCompanyData 及其coresponding 状态道具.

    props.getCompanyData()
    props.companyState
    

    使用 HOC,您可以重用功能,但您不共享公共状态。

    如果你想共享共同的状态,那么你必须将它作为道具从他们共同的父母那里传递

    【讨论】:

    • 他们是我的兄弟姐妹,但是在将示例转换为工作代码时遇到问题,什么是 HOC?
    • 我建议你看看SWR
    • 谢谢@Riwen,我来看看,不是数据获取给我带来了问题,而是从另一个组件调用函数。 HOC 看起来,……高级。
    • 它只是一个创建组件的函数,它包装给定的组件并将道具传递给它。而已
    【解决方案2】:

    最后我选择了一个共同的父解决方案,因为这对我来说更容易理解:

    我创建了一个公司页面组件:

    'use strict';
    
    const CompanySelector = 'company-selector';
    const CompanyData = 'company-data';
    
    class CompanyPage extends React.Component {
    
    constructor(props) {
        super(props);
    
        this.state = {
            currentItem: 0
        };
    
        this.onSelect = this.onSelect.bind(this);
    }
    
    onSelect(companyID) {
        this.setState({ currentItem: companyID });
    }
    
    render() {
        return <>
            <div class="row">
                <CompanySelector onSelect={this.onSelect} />
            </div>
            <div class="row mt-4">
                <CompanyData fetchData={this.state.currentItem} />
            </div>
        </>
    }
    }
    
    const elePage = document.getElementById('company-page');
    const rootPage = ReactDOM.createRoot(elePage);
    rootPage.render(<CompanyPage />);
    

    然后,我通过将 window.getCompanyData 行替换为 handleChange 方法中的以下内容来调整 CompanySelector 组件:

        if (this.props.onSelect) {
            this.props.onSelect(evt.target.value);
        }
    

    然后我进入 CompanyData 类并进行了以下更改:

    在构造函数的最后:

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

    React 的新方法表明某些事情发生了变化:

    componentDidUpdate(prevProps, prevState) {
        if (prevProps.fetchData !== this.props.fetchData) {
            if (this.props.fetchData) {
                this.loadData(this.props.fetchData);
            }
        }
    }
    

    从 API 方法加载数据(相当于 window.getCompanyData):

    loadData(id) {
        //API call using axios excluded for brevity
    }
    

    在刀片模板中:

    <div class="row">
        <div id="company-page" class="company-page">
            <div id="company-selector" class="company-selector"></div>
            <div id="company-data" class="company-data"></div>
        </div>
    </div>
    

    【讨论】:

      猜你喜欢
      • 2017-12-09
      • 2016-11-09
      • 2017-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-05
      • 2017-08-19
      相关资源
      最近更新 更多