如何在点击元素时调用已连接Redux的类中的方法?
问题描述
现有如下React+Redux代码:
import { connect } from "react-redux"; class FirstClass extends React.Component{ callMeFromSecondClass(){ //code to execute } } export default connect(mapStateToProps)(FirstClass); class SecondClass extends React.Component{ render(){ <div onClick={FirstClass.callMeFromSecondClass}></div> } }
需求:点击SecondClass中的div元素时,调用FirstClass类中的callMeFromSecondClass方法,该如何实现?
问题分析
原代码的问题很明显:callMeFromSecondClass是FirstClass的实例方法,不是静态方法,直接通过FirstClass.callMeFromSecondClass调用肯定报错;而且如果两个组件没有直接的父子关系或状态共享机制,根本没法直接跨组件调用实例方法。
解决方案
方案1:通过父组件传递回调(组件有层级关系时)
如果FirstClass和SecondClass有共同的父组件,就可以在父组件里拿到FirstClass的实例引用,再把回调传给SecondClass:
import { connect } from "react-redux"; class ParentComponent extends React.Component { firstClassRef = React.createRef(); handleCallFirstClassMethod = () => { // 可选链避免实例未挂载时调用报错 this.firstClassRef.current?.callMeFromSecondClass(); }; render() { return ( <> <FirstClass ref={this.firstClassRef} /> <SecondClass onClick={this.handleCallFirstClassMethod} /> </> ); } } class FirstClass extends React.Component{ callMeFromSecondClass(){ console.log("FirstClass的方法被调用了"); // 这里写你的业务代码 } } export default connect(mapStateToProps)(FirstClass); class SecondClass extends React.Component{ render(){ return <div onClick={this.props.onClick}>点击触发</div> } }
方案2:用Redux状态触发(无直接层级关系时)
要是两个组件没直接层级,就可以借助Redux的状态来触发方法调用:
- 先定义一个action,用来标记需要调用FirstClass的方法
- 在FirstClass里监听Redux状态变化,状态触发时执行方法
- 在SecondClass的点击事件里dispatch这个action
// 第一步:定义action和reducer const CALL_FIRST_CLASS_METHOD = 'CALL_FIRST_CLASS_METHOD'; const RESET_CALL_FLAG = 'RESET_CALL_FLAG'; // 触发调用的action export const callFirstClassMethod = () => ({ type: CALL_FIRST_CLASS_METHOD }); // 重置标记的action,避免重复触发 export const resetCallFlag = () => ({ type: RESET_CALL_FLAG }); const initialState = { shouldCallMethod: false }; export const reducer = (state = initialState, action) => { switch(action.type) { case CALL_FIRST_CLASS_METHOD: return { ...state, shouldCallMethod: true }; case RESET_CALL_FLAG: return { ...state, shouldCallMethod: false }; default: return state; } }; // 第二步:修改FirstClass,监听状态 import { connect } from "react-redux"; import { callFirstClassMethod, resetCallFlag } from './actions'; class FirstClass extends React.Component{ componentDidUpdate(prevProps) { // 当状态从false变true时,执行方法 if (this.props.shouldCallMethod && !prevProps.shouldCallMethod) { this.callMeFromSecondClass(); // 执行完重置状态 this.props.dispatch(resetCallFlag()); } } callMeFromSecondClass(){ console.log("FirstClass的方法被调用了"); // 业务代码写这里 } } const mapStateToProps = (state) => ({ shouldCallMethod: state.shouldCallMethod }); export default connect(mapStateToProps)(FirstClass); // 第三步:修改SecondClass,dispatch action class SecondClass extends React.Component{ handleClick = () => { this.props.dispatch(callFirstClassMethod()); } render(){ return <div onClick={this.handleClick}>点击触发</div> } } export default connect()(SecondClass);
方案3:用React Context(无直接层级关系时)
通过Context共享FirstClass的实例方法也是个不错的选择:
// 创建Context const MethodContext = React.createContext(); // 父组件提供Context class ParentComponent extends React.Component { firstClassRef = React.createRef(); // 返回一个可以调用FirstClass方法的函数 getCallMethod = () => { return () => this.firstClassRef.current?.callMeFromSecondClass(); }; render() { return ( <MethodContext.Provider value={this.getCallMethod()}> <FirstClass ref={this.firstClassRef} /> <SecondClass /> </MethodContext.Provider> ); } } class FirstClass extends React.Component{ callMeFromSecondClass(){ console.log("FirstClass的方法被调用了"); // 业务代码 } } export default connect(mapStateToProps)(FirstClass); // SecondClass消费Context class SecondClass extends React.Component{ static contextType = MethodContext; render(){ return <div onClick={this.context}>点击触发</div> } }
内容的提问来源于stack exchange,提问作者Vitaly
相关产品推荐
相关产品推荐

