首页 文章

如何将redux存储中的封装ui状态映射到具有react-redux的props?

提问于
浏览
3

我无法弄清楚如何组合ui小部件缩减器并对渲染树进行串联反应,以后我可以使用react-redux将渲染树的结果redux存储映射到渲染树中的道具 .

假设这样的设置 . 我正在尝试创建一个可以在任何应用程序中随处使用的NameWidget:

NameView.jsx:
...
render() {
  return <div> Name: {this.props.name} </div>;
}
...

====

NameAction.js:
...
export const CHANGE_NAME = 'CHANGE_NAME';
...
export function changeNameAction(newName) {
  return {
    type: CHANGE_NAME,
    payload: newName,
  };
}

====

NameReducer.js:

import { CHANGE_NAME } from './NameAction';

function ui(state = {name: ''}, action) {
  switch(action.type) {
    case(CHANGE_NAME):
      return Object.assign({}, state, {name: action.payload});
      break;
    default:
      return state;
  }
}

export default ui;

====

NameWidget.js:

import { connect } from 'react-redux';
import { NameView } from './NameView';

const mapStateToProps = (state) => {
  return {
    name: state.name,
  };
};

const NameWidget = connect(
  mapStateToProps
)(NameView);

export default NameWidget;

如果我直接使用NameWidget,我将没有问题:

NameApp.jsx:

import { createStore } from 'redux';
import app from './NameReducers';
let store = createStore(app);
...
function render() {
  return (
    <Provider store={store}>
      <NameWidget/>
    </Provider>
  );
}

但是,我不知道如何制作这种模块化 . 我实际上无法把这个Widget放到其他任何东西上 . 假设我想这样做:

EncapsulatingView.jsx:
...
render() {
  return (
    <div>
      <NameWidget/>
      <SomeOtherReduxWidget/>
    </div>
  );
}
...

====

EncapsulatingReducer.js:
import { combineReducers } from 'redux'
import nameWidget from '../name/NameReducer';
import someOtherWidget from '../someOther/SomeOtherReduxWidgetReducer';

export default combineReducers({nameWidget, someOtherWidget});

(我希望其余代码包括用于Encapsulating *的connect()和createStore()是显而易见的 . )

只要所有封装视图中的所有操作都具有唯一类型,此_2404583就可以工作 . 但问题是NameWidget的mapStateToProps;它需要从上面改变以使用到其商店部分的新路径:

...
const mapStateToProps = (state) => {
  return {
    name: state.nameWidget.name,
  };
};
...

依此类推 - 依赖于祖先如何结合Reducers()来定义他们更宏伟的超级小部件和应用程序,后代不得不改变mapStateToProps()的补偿方式 . 这打破了代码的封装和可重用性,我不知道如何在react-redux中解决它 . 如何通过组合combineReducers()来定义小部件,然后将生成的商店映射到那些小部件的道具,以一种一次性写入的方式?

(没有任何东西,重复的combineReducers()创建一个自下而上的形状似乎很奇怪,但mapStateToProps()似乎采用自上而下的“绝对路径”方法来查找该形状 . )

2 回答

  • 0

    有趣的问题 . 我想知道它是否符合您的目的,要求父进程生成guid并通过props传递,然后您只需将其用作您的小部件实例的状态对象的索引 . 因此,无论何时您要创建此小部件的新实例,您都需要在父级中为其创建一个ID,然后在道具中将其传递下来,然后它将可用于 connect 方法以在mapStateToProps和mapDispatchToProps中使用 . 我认为理论上你甚至可以自己创建这个父组件,它在使用时可能是透明的,只需使用componentDidMount生成一个新的guid来存储在组件状态并传递给子组件 .

  • 1

    我给了John这个问题的功劳,因为他基本上为答案提供了正确的魔力,通过mapStateToProps()的ownProps函数arg传递商店“路由”逻辑 . 但我更喜欢自己的旋转 . 基本上,每当你在EncapsulatingReducer.js中组合Reducers()时,你必须记住在EncapsulatingView.js中传递一个uiStorePath道具:

    New NameWidget.js:
    
    const _ = require('lodash');
    import { connect } from 'react-redux';
    import { NameView } from './NameView';
    
    const mapStateToProps = (state, props) => {
      const uiStore = (
        (ownProps && _.has(ownProps, 'uiStorePath') && ownProps.uiStorePath &&
            ownProps.uiStorePath.length) ? 
          _.get(state, ownProps.uiStorePath) :  // deep get...old versions of lodash would _.deepGet()
          state
      );
    
      return {
        name: uiStore.name,
      };
    };
    
    const NameWidget = connect(
      mapStateToProps
    )(NameView);
    
    export default NameWidget;
    

    ====

    EncapsulatingView.js:
    
    ...
    render() {
      const uiStorePathBase = ((this.props.uiStorePath &&         
          this.props.uiStorePath.length) ?
        this.props.uiStorePath + '.' :
        ''
      );
      return (
        <div> 
          <NameWidget uiStorePath={uiStorePathBase+"nameWidget"}/>
          <SomeOtherWidget uiStorePath={uiStorePathBase+"someOtherWidget"/>
        </div>
      );
    }
    ...
    

相关问题