在反应组件之外移动处理程序函数 [英] Moving handler functions outside of react component

查看:25
本文介绍了在反应组件之外移动处理程序函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I created a reusable date picker component that I want to use throughout my React app. The issue that I'm running into is that the handler functions that get called during user interactions are identical in every React component where I use my date picker. This means I need to move them to an external file.

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

The question is once I move thess functions to an external file which is NOT a React component, how will I access the store and dispatch function?

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

Did some research and came across the idea of using middleware but as far as I know middleware is supposed to go in between action creators and reducers. In this particular case, I'm simply moving my handler functions to an external file, not really inserting anything in between action creators and reducers.

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

Say, my external file looks like this:

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 行特别困惑.

I tried to kind of modify what things look like in a React component and I'm not really sure if this makes sense. I'm particularly confused about the connect line at the bottom.

推荐答案

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

There are two ways you might handle this. The first is currying, which is wrapping your event handlers into a function that takes this.props and allows the inner event handler to use them. For example in your handleChangeDecadeStart function you could do something like this:

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);  
  }
}

然后在你的组件的渲染函数中你会这样做:

Then in your component's render function you would to this:

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

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

This way the event handler will have access to this.props without actually being inside the class.

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

The connect line at the end connects the store to your class, so it should receive your React component class as the final argument like this:

connect(mapStateToProps, mapDispatchToProps)(MyReactComponent)

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

The second, and in my opinion better way is to use a Higher-Order-Component. An HOC is just like the connect function, a function that takes a component and returns a component wrapping it adding some functionality. An example implementation:

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} />
  }
}

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

Then, when exporting your class you would do something like this:

export default wrapWithHandlers(MyComponent)

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

The function will wrap your component with a Higher-Order Component that provides it with the handlers needed, and you can re-use it with other Components. In your case, though, you also use connect, so your code will be:

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

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

This pattern of a function calling a function calling a function etc.. is called function composition, which can be better expressed using the compose function in redux, in which case your code would be:

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

export default enhancer(MyComponent);

虽然不是自己做,但有很多库可以为您提供这种开箱即用的 HOC,recompose 就是一个很好的例子.查看他们的 withHandlers 函数,该函数为您提供了您需要的确切功能.

Instead of doing this yourself, though, there are a lot of libraries out there that provide you with this kind of HOC out-of-the-box, recompose being an excellent example. Check out their withHandlers function which provides you with the exact functionality you need.

这篇关于在反应组件之外移动处理程序函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆