Reactjs React/Redux/Immutable-关于带有子组件的HOC策略的混淆

Reactjs React/Redux/Immutable-关于带有子组件的HOC策略的混淆,reactjs,react-redux,immutability,immutable.js,higher-order-components,Reactjs,React Redux,Immutability,Immutable.js,Higher Order Components,我希望我能以问题的形式理解所有这些。在过去的7个多小时里,我一直在努力解决这个问题,但没有成功。我的大脑在这一点上已经干涸了,不管怎样,我已经走到了死胡同 我正在使用react 15.6.1、redux 3.7.1、react redux 5.0.5、redux immutable 4.0.0、redux form 7.2.0、react select 1.2.1 我的应用程序具有搜索功能,字段A和字段B使用两种不同的表单(不同页面的不同表单)。我不认为这是这个问题的关键,但我正在使用redux

我希望我能以问题的形式理解所有这些。在过去的7个多小时里,我一直在努力解决这个问题,但没有成功。我的大脑在这一点上已经干涸了,不管怎样,我已经走到了死胡同

我正在使用react 15.6.1、redux 3.7.1、react redux 5.0.5、redux immutable 4.0.0、redux form 7.2.0、react select 1.2.1

我的应用程序具有搜索功能,字段A和字段B使用两种不同的表单(不同页面的不同表单)。我不认为这是这个问题的关键,但我正在使用redux表单和react select作为表单和搜索字段。我将用户输入的搜索条件存储在我的搜索缩减器中,以同步不同表单中选择列表的自动填充等

redux表单-->react select(字段A) ---->反应选择(字段B)

我的搜索缩减器正在initialState()中使用Immutable.fromJs()。减速器按预期工作。我的问题是在何处使用HOC,以便将从reducer返回的Map对象转换为react select组件所需的JS数组

MainSearchForm.js:-

import React, {Component} from 'react'
import { Field, reduxForm } from 'redux-form'
import { connect } from 'react-redux'

import FormFieldA from './FormFieldA'
import FormFieldB from './FormFieldB'

class MainSearchForm extends Component {

  render() {

    return(
    <form>
      <FormFieldA options={this.props.fieldAoptions}/>
      <FormFieldB options={this.props.fieldBoptions}/>
    </form>
    )
  }
}

function mapStateToProps ({Search}, props) {
  return {
    fieldAoptions: Search.get('fieldAoptions'),
    fieldBoptions: Search.get('fieldBoptions'),
  }
}

MainSearchForm = connect(mapStateToProps,{})(MainSearchForm);

export default reduxForm({
  form: 'main-search',
})(MainSearchForm)
我可以使用Immutable.toJS()来转换它,但Redux官方指南出于性能原因建议不要这样做,建议使用(我假设是可重用的)HOC组件来解析到JS数组的不可变映射

我的问题是,我将如何将其合并?正如您在上面的代码中所看到的,现在我的MainSearchForm正在连接到Redux存储,以检索作为react select options props选项所需的选项数据。答案是不使用MainSearchForm,而是为MainSearchForm提供的每个字段使用一个中间组件,该中间组件在使用connect之前调用HOC,如指南中所示:-

import React from 'react'
import { Iterable } from 'immutable'

export const toJS = WrappedComponent => wrappedComponentProps => {
  const KEY = 0
  const VALUE = 1

  const propsJS = Object.entries(
    wrappedComponentProps
  ).reduce((newProps, wrappedComponentProp) => {
    newProps[wrappedComponentProp[KEY]] = Iterable.isIterable(
      wrappedComponentProp[VALUE]
    )
      ? wrappedComponentProp[VALUE].toJS()
      : wrappedComponentProp[VALUE]
    return newProps
  }, {})

  return <WrappedComponent {...propsJS} />
}
摘自Redux不可变指南:-

import React from 'react'
import { Iterable } from 'immutable'

export const toJS = WrappedComponent => wrappedComponentProps => {
  const KEY = 0
  const VALUE = 1

  const propsJS = Object.entries(
    wrappedComponentProps
  ).reduce((newProps, wrappedComponentProp) => {
    newProps[wrappedComponentProp[KEY]] = Iterable.isIterable(
      wrappedComponentProp[VALUE]
    )
      ? wrappedComponentProp[VALUE].toJS()
      : wrappedComponentProp[VALUE]
    return newProps
  }, {})

  return <WrappedComponent {...propsJS} />
}
这是最佳做法吗


我将真诚地感谢在这方面的任何帮助。这是我第一次使用HOC&Immutable,它有很多优点。但是我想我终于掌握了这个范例。

不要太担心最佳实践,今天的最佳实践就是明天的反模式。不要误解我,知道什么是做事情的“最好”方式是很好的,但最好的方式总是相对的,所以要考虑到这一点

这个想法是,您的FormFieldA和FormFieldB不应该关心可能出现的redux、immutable、foobar、bajouras、WTVlibrary或Tools

因此,对于不可变项,您的HOC应该位于您的MainSearchForm

import React, {Component} from 'react'
import { Field, reduxForm } from 'redux-form'
import { connect } from 'react-redux'

import { toJS } from './to-js'

import FormFieldA from './FormFieldA'
import FormFieldB from './FormFieldB'

class MainSearchForm extends Component {

  render() {

    return(
    <form>
      <FormFieldA options={this.props.fieldAoptions}/>
      <FormFieldB options={this.props.fieldBoptions}/>
    </form>
    )
  }
}

function mapStateToProps ({Search}, props) {
  return {
    fieldAoptions: Search.get('fieldAoptions'),
    fieldBoptions: Search.get('fieldBoptions'),
  }
}

MainSearchForm = connect(mapStateToProps,{})(toJS(MainSearchForm));

export default reduxForm({
  form: 'main-search',
})(MainSearchForm)

FWIW我在所有连接的组件上使用redux文档中的toJS HOC。非常感谢各位。我已经实现了你的代码Fabio,效果不错。当我在这里问你的时候,我已经完全精神崩溃了,非常感谢你。对于其他可能听从Fabio建议的人,请注意,他在connect()内部实现了toJS(),而不是MapStateTrops(),因为后者会妨碍性能,因为如果状态的任何部分发生更改,则会强制重新命名,因为如果转换发生在MapStateTrops()中,React会将状态的所有部分视为新对象。请参阅我在问题中链接的官方Redux文档以供参考。
import { connect } from 'react-redux'
import { toJS } from './to-js'
import FormFieldA from './FormFieldA'

    function mapStateToProps ({Search}, props) {
      return {
        fieldAoptions: Search.get('fieldAoptions'),
      }
    }
export default connect(mapStateToProps)(toJS(FormFieldA))
import React, {Component} from 'react'
import { Field, reduxForm } from 'redux-form'
import { connect } from 'react-redux'

import { toJS } from './to-js'

import FormFieldA from './FormFieldA'
import FormFieldB from './FormFieldB'

class MainSearchForm extends Component {

  render() {

    return(
    <form>
      <FormFieldA options={this.props.fieldAoptions}/>
      <FormFieldB options={this.props.fieldBoptions}/>
    </form>
    )
  }
}

function mapStateToProps ({Search}, props) {
  return {
    fieldAoptions: Search.get('fieldAoptions'),
    fieldBoptions: Search.get('fieldBoptions'),
  }
}

MainSearchForm = connect(mapStateToProps,{})(toJS(MainSearchForm));

export default reduxForm({
  form: 'main-search',
})(MainSearchForm)
import React, {Component} from 'react'
import FormFieldA from './FormFieldA'
import FormFieldB from './FormFieldB'

class MainSearchForm extends Component {

  render() {

    return(
    <form>
      <FormFieldA options={this.props.fieldAoptions}/>
      <FormFieldB options={this.props.fieldBoptions}/>
    </form>
    )
  }
}

export default MainSearchForm
import { Field, reduxForm } from 'redux-form'
import { connect } from 'react-redux'
import MainSearchForm from './MainSearchForm'
import { toJS } from './to-js'

function mapStateToProps ({Search}, props) {
  return {
    fieldAoptions: Search.get('fieldAoptions'),
    fieldBoptions: Search.get('fieldBoptions'),
  }
}

const MainSearchFormContainer = connect(mapStateToProps,{})(toJS(MainSearchForm));

export default reduxForm({
  form: 'main-search',
})(MainSearchFormContainer)