在react组件之外移动处理程序函数

IT技术 reactjs redux react-redux
2021-05-13 23:01:06

我创建了一个可重用的日期选择器组件,我想在整个 React 应用程序中使用它。我遇到的问题是,在我使用日期选择器的每个 React 组件中,在用户交互期间调用的处理函数都是相同的。这意味着我需要将它们移动到外部文件。

问题是一旦我将 thess 函数移动到一个不是 React 组件的外部文件,我将如何访问存储和调度函数?

做了一些研究并遇到了使用中间件的想法,但据我所知,中间件应该介于动作创建者和减速器之间。在这种特殊情况下,我只是将我的处理程序函数移动到一个外部文件,而不是真正在动作创建者和减速器之间插入任何东西。

说,我的外部文件是这样的:

import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

// Import actions
import * as myActions from '../actions/myActions';

export const handleChangeDecadeStart = (datePickerId, value) => {

   // Get current decade start
   const currentDecadeStart = this.props.decadeStart;

   // Set new decade start value
   if(value === "prev") {
         return this.props.actions.setDecadeStart(datePickerId, currentDecadeStart - 10);  
   } else {
         return this.props.actions.setDecadeStart(datePickerId, currentDecadeStart + 10);  
   }
}

export const setDate = (datePickerId, value) => {

   return this.props.actions.setDate(datePickerId, value);
}

function mapStateToProps(state) {

    return {
        decadeStart: state.calendars.decadeStart,
    };
}

function mapDispatchToProps(dispatch) {

    return {
        actions: bindActionCreators(myActions, dispatch)
    };
}

connect(mapStateToProps, mapDispatchToProps)(???);

我试图修改 React 组件中的内容,但我不确定这是否有意义。connect对底部线特别困惑

1个回答

有两种方法可以处理这个问题。第一个是柯里化,它将您的事件处理程序包装到一个函数中,该函数接受this.props并允许内部事件处理程序使用它们。例如,在您的handleChangeDecadeStart函数中,您可以执行以下操作:

const handleChangeDecadeStart = props => (datePickerId, value) => {

  // Get current decade start
  const currentDecadeStart = this.props.decadeStart;

  // Set new decade start value
  if(value === "prev") {
     return this.props.actions.setDecadeStart(datePickerId, 
    currentDecadeStart - 10);  
  } else {
     return this.props.actions.setDecadeStart(datePickerId, 
    currentDecadeStart + 10);  
  }
}

然后在组件的渲染函数中,您将执行以下操作:

return (
   <YourComponent onChangeDecadeStart={handleChangeDecadeStart(this.props)}/>
)

这样,事件处理程序就可以访问 this.props 而实际上不在类中。

最后的连接线将 store 连接到您的类,因此它应该接收您的 React 组件类作为最终参数,如下所示:

connect(mapStateToProps, mapDispatchToProps)(MyReactComponent)

第二种,在我看来更好的方法是使用高阶组件。一个HOC就像连接函数一样,一个函数接受一个组件并返回一个包含它的组件并添加一些功能。一个示例实现:

const wrapWithHandlers = Component => class Wrapper extends Component {
  handleChangeDecadeStart = (datePickerId, value) => {

     // Get current decade start
     const currentDecadeStart = this.props.decadeStart;

     // Set new decade start value
     if(value === "prev") {
       return this.props.actions.setDecadeStart(datePickerId, currentDecadeStart - 10);  
     } else {
       return this.props.actions.setDecadeStart(datePickerId, currentDecadeStart + 10);  
     }
  }

  render() {
    return <Component onChangeDecadeStart={this.handleChangeDecadeStart} {...this.props} />
  }
}

然后,在导出类时,您将执行以下操作:

export default wrapWithHandlers(MyComponent)

该函数将使用高阶组件包装您的组件,该组件为其提供所需的处理程序,您可以将其与其他组件重用。但是,在您的情况下,您也使用连接,因此您的代码将是:

export default connect(mapStateToProps, mapDispatchToProps)(wrapWithHandlers(MyComponent))

这种函数调用函数调用函数等的模式称为函数组合,可以使用 redux 中的 compose 函数更好地表达,在这种情况下,您的代码将是:

import { compose } from 'redux'
...
const enhancer = compose(connect(mapStateToProps, mapDispatchToProps), wrapWithHandlers);

export default enhancer(MyComponent);

不过,与其自己做这件事,还有很多库可以为您提供这种开箱即用的 HOC,recompose就是一个很好的例子。查看他们的withHandlers函数,它为您提供所需的确切功能。