在反应组件

时间:2017-08-09 19:45:32

标签: reactjs redux react-redux

我创建了一个可重复使用的日期选择器组件,我想在整个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 个答案:

答案 0 :(得分:1)

有两种方法可以解决这个问题。第一个是currying,它将事件处理程序包装到一个带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而不会真正进入类。

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

connect(mapStateToProps, mapDispatchToProps)(MyReactComponent)

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

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)

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

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功能,它可以为您提供所需的确切功能。