【问题标题】:Realize a confirm component with react, redux and promise用react、redux和promise实现一个confirm组件
【发布时间】:2017-01-18 14:45:42
【问题描述】:

我尝试使用 redux 和原生 promise 构建一个通用的确认组件。我在这里阅读了 Dan Abramovs 的解决方案:How can I display a modal dialog in Redux that performs asynchronous actions?,但我正在寻找更通用的方法。 基本上我想这样做:

confirm({
  type: 'warning',
  title: 'Are you sure?',
  description: 'Would you like to do this action?',
  confirmLabel: 'Yes',
  abortLabel: 'Abort'
})
.then(() => {
  // do something after promise is resolved
})

confirm 方法基本上是打开 modal 并返回一个 promise。在 promise 中,我订阅了我的 redux 存储,监听状态变化并解决或拒绝 promise:

export const confirm = function(settings) {
  // first dispatch openConfirmModal with given props
  store.dispatch(
    openConfirmModal({
      ...settings
    })
  );

  // return a promise that subscribes to redux store
  // see: http://redux.js.org/docs/api/Store.html#subscribe
  // on stateChanges check for resolved/rejected
  // if resolved or rejected:
  // - dispatch closeConfirmModal
  // - resolve or reject the promise
  // - unsubscribe to store
  return new Promise((resolve, reject) => {

    function handleStateChange() {
      let newState = store.getState();

      if (newState.confirmModal.resolved) {
        store.dispatch(closeConfirmModal());
        resolve();
        unsubscribe();
      }

      if (newState.confirmModal.rejected) {
        store.dispatch(closeConfirmModal());
        reject();
        unsubscribe();
      }
    }

    let unsubscribe = store.subscribe(handleStateChange);
  })


}

我的确认组件已连接到 redux 商店,并且在某种布局组件中包含一次 - 因此它可用于应用程序中的所有路由:

class ConfirmModal extends Component {

  constructor(props) {
    super(props)
  }

  confirm() {
    this.props.dispatch(resolveConfirmModal());
  }

  abort() {
    this.props.dispatch(rejectConfirmModal());
  }

  render() {
    // my modal window 
  }
}

export default connect(
  state => ({
    confirmModal: state.confirmModal
  })
)(ConfirmModal);

Reducer/Action 看起来像这样:

export const openConfirmModal = (settings) => {
  return {
    type: 'OPEN_CONFIRM_MODAL',
    settings
  };
};

export const resolveConfirmModal = () => {
  return {
    type: 'RESOLVE_CONFIRM_MODAL'
  };
};

export const rejectConfirmModal = () => {
  return {
    type: 'REJECT_CONFIRM_MODAL'
  };
};

export const closeConfirmModal = () => {
  return {
    type: 'CLOSE_CONFIRM_MODAL'
  };
};

const initialState = {
  open: false,
  type: 'info',
  title: 'Are you sure?',
  description: 'Are you sure you want to do this action?',
  confirmLabel: 'Yes',
  abortLabel: 'Abort',
};

export const ConfirmModalReducer = (state = initialState, action) => {
  switch (action.type) {

    case 'OPEN_CONFIRM_MODAL':
      return { ...action.settings, open: true };

    case 'RESOLVE_CONFIRM_MODAL':
      return { ...state, resolved: true };

    case 'REJECT_CONFIRM_MODAL':
      return { ...state, rejected: true };

    case 'CLOSE_CONFIRM_MODAL':
      return initialState;

    default:
      return state;
  }
};

redux 部分正在工作。我的确认窗口可以打开/关闭并根据我的选项进行渲染。但是我如何在我的确认方法中定义一个可以在我的组件中解决的承诺?我如何将所有东西连接起来?

找到一个可行的解决方案!

找到了一个几乎是我正在寻找的解决方案:

你怎么看?

【问题讨论】:

  • 可以加closeConfirmModal()代码吗?
  • 完成。添加了动作和减速器。也许使用异步操作会更好。但到目前为止,我试图在 redux 部分保持简单。
  • @d-bro82 你有这个例子用 javascript 代替 cofeescript 吗?

标签: reactjs redux react-redux


【解决方案1】:

嗯,你可以做到,但它不会很漂亮。基本上,您需要在 confirm() 旁边有一张未完成承诺的地图:

var outstandingModals = {}
const confirm = function(settings) {
    return new Promise((resolve, reject) => {
        let id = uuid.v4();
        outstandingModals = resolve;
        store.dispatch(
        openConfirmModal({
            ...settings,
            confirmationId: id,
        })
    );
}

然后:

case 'CLOSE_CONFIRM_MODAL':
    let resolve = outstandingModals[state.confirmationId];
    if (resolve) {
        resolve();
        delete outstandingModals[state.confirmationId];
    }
    return initialState;

就像我说的 - 丑陋。我认为没有比使用 Promise 做得更好的了。

但是你可以通过不使用 Promise 做得更好。我要做的就是在必要时简单地渲染一个 Confirm 组件,比如:

render() {
    return <div>
       ... My stuff ...
        {confirmationNecessary && <Confirm text='Are you sure?' onAction={this.thenConfirmed}/>}
       </div>
}

confirmationNecessary 可以来自this.state 或来自商店。

【讨论】:

  • 非常感谢。但是通过这种方法,我必须将我的操作传递给我的确认组件,并且我必须在我想要显示确认的每个其他组件中包含确认组件。这是我试图避免的。我的想法是一个包含一次并且不需要知道确认后做什么的组件。基本喜欢jameskleeh.com/angular-confirm
  • 没关系。您至少可以使用我建议的第一个选项 - 使用 outstandingPromises 映射。不过,我不会真正使用 redux。我会实现一些自定义的东西,它使用 react 的 context 属性。
【解决方案2】:

我写了一篇博文,讨论了一种管理“通用”模态的可能方法:Posts on PacktPub: "Generic Redux Modals" and "Building Better Bundles"

基本思想是请求模态的代码可以包含一个预先编写的动作作为道具,并且模态一旦关闭就可以调度该动作。

redux-promising-modals 还有一个看起来很有趣的库,它似乎通过中间件实现了模态结果承诺。

【讨论】:

  • 谢谢,我还阅读了关于 StackOverflow 的 Dan Abramovs 方法。您的博文非常有趣,我喜欢将动作作为有效负载进行调度的想法。我会试一试,但我错过了承诺部分:/
  • 是的,我的方法避免了承诺和回调,而是在完成时分派一个动作。如果你真的想要一个承诺,你可以试试promising-modals 库。
【解决方案3】:

可能这样:)

export const MsgBox = {
	okCancel : s =>
		new Promise((ok, cancel) =>
			confirm(s) ? ok() : cancel() ),

......etc

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多