Redux: 如何在不使用@connect的情况下调用动作?

创建于 2015-07-30  ·  32评论  ·  资料来源: reduxjs/redux

我有一个标头容器,它使用以下方式将图像数据(URL,大小)传递给标头组件

@connect(state => ({
  header: state.header
}))
export default class HeaderContainer extends Component {
 /// pass props.header data to child Header which renders image.
}

然后,我还有另一个组件需要调用标头操作才能更新标头状态。 它不使用状态,而只是触发动作。 Afaik我需要执行以下操作:

const { dispatch } = this.props
const actions = bindActionCreators(headerActions, dispatch)

问题是,仅当您使用@connect装饰器时,this.props.dispatch才似乎可用。 第二个组件对标头状态完全不感兴趣。 我真的需要在这里使用connect还是可以以其他方式绑定动作? 如果我不使用数据,则使用@connect感觉不对。

question

最有用的评论

您可以将dispatch作为道具手动传递给该组件。

所有32条评论

我不确定这是否是一种“正确”的方式,但是您可以通过上下文访问商店。 例如,请参见Connector组件:
https://github.com/gaearon/react-redux/blob/master/src/components/createConnector.js

我不跟着你。 我可以使用@connect很好地访问商店。 我正在寻找一种无需使用@connect即可绑定/调用组件中的动作的方法。

dispatch函数是商店的一种方法。 如果您在组件中需要它,但不想使用@connect ,则可以通过上下文访问存储并使用其分派方法:

class MyComponent extends Compoenent {
    static contextTypes = {
        store: React.PropTypes.object.isRequired,
    }

    render() {
         const { dispatch } = this.context.store
         const actions = bindActionCreators(headerActions, dispatch)
    }
}

您应该从父组件或已绑定到该调度的动作中传递调度。 这是我认为的方式,上下文也可以工作,尽管这是一种解决方法

感谢您的解释! 我明白了

您可以将dispatch作为道具手动传递给该组件。

我对此问题也感到有些困惑。

如果我理解正确的话,我们需要将有dispatch可以通过组件的道具(能够从该组件调度动作)或给予已经绑定到行动创dispatch ,从父组件。 但是这两个解决方案都需要有一个connect ed的父组件,以便可以通过其props对其进行调度。

因此,最后我们只是将dispatch依赖关系转移到父组件上。 如果没有这样的connect ed父母,您将如何做?

例如,如果我们处于组件的深层次结构中,该怎么办:

Provider
  Router
    AppContainer
     ...
       ...
         ...
           TheComponentThatNeedDispatch

如果没有父母需要连接到redux状态?

将分发作为组件使用connect的副作用似乎使我们处于这样一个情况,即必须以其父对象为connect ed能够进行dispatch个动作。 这感觉很奇怪,因为组件执行dispatch动作的能力与使用connect从redux状态读取的需求之间应该没有任何关联。

我知道我们仍然可以从组件上下文访问dispatch (通过store.dispatch ),但是由于这不是推荐的方式...

你怎么看待这件事?

谢谢!

这感觉很奇怪,因为组件分派动作的能力与使用connect来读取redux状态的需求之间应该没有任何关联。

为什么奇怪呢? 将connect视为“连接到Redux”,而不仅仅是“连接到Redux状态的一部分”。 那就有意义了:要能够dispatch要么组件本身,要么它的某些父组件需要connect() ed到Redux。

使用当前的React Redux API,如果不选择状态就无法连接到Redux。 您必须编写类似connect(state => ({}))(MyComponent) (返回空对象)。 这就是为什么我们正在探索使其成为dispatch头等公民的API并计划添加一个API来“仅dispatch ”的原因。

这有意义吗?

将connect视为“ connect to Redux”,而不仅仅是“ connect to Redux state的一部分”。

现在完全有意义:)。

等不及要使用新的API了

非常感谢,使用Redux是一件乐事!

看起来很棒!

@gaearon嘿,丹,您能给我一个关于如何将bindActionCreators与嵌套组件一起使用的提示:

“ AddProduct”-连接到redux(请参见下文)
__“产品列表”
____“ ProductView”。

我希望ProductView能够发送,但是只有主设备“添加产品”具有:

function appState(state) {
    return {...};
}

export default connect(appState)(AddProduct)

您也可以connect()嵌套组件,也可以将dispatch传递给它作为道具。

感谢Dan,非常感谢您的帮助。 真的也喜欢redux!

另一个问题,如果我可以:
我可以从reducer本身内部放置服务器API发布请求吗?
当我发布到数据库(mongodb)时,该项目将获得一个我想在其redux状态下使用的“ _id”。 应该将分派作为POST请求的回调放置吗?

谢谢

我可以从reducer本身内部放置服务器API发布请求吗?

绝对不是,reducer必须是没有任何副作用的纯函数。

当我发布到数据库(mongodb)时,该项目将获得一个我想在其redux状态下使用的“ _id”。 应该将分派作为POST请求的回调放置吗?

是。

请参阅此指南: http :

感谢Dan,工作出色(y)

如果即时通讯使用服务器渲染,可以说让当前用户登录,
我可以跳过从商店的异步获取,并在服务器上执行此操作吗?

如果即时通讯使用服务器渲染进行操作,比如说让当前用户登录,我是否可以跳过从商店获取的异步操作,并在服务器上执行此操作?

您可以在服务器上创建存储,等待异步操作完成,然后进行渲染。
另请参阅http://rackt.github.io/redux/docs/recipes/ServerRendering.html

我可能错过了一些关键的东西,但是为什么不在应用初始化期间仅部分应用分派到所有动作创建者上呢? 然后,您可以在任何地方致电,而不必担心如何获取要分发的引用。

@mpoisot :因为您必须在应用启动时知道,导入,绑定和分发_every_个潜在动作创建者。 除其他外,这对诸如代码拆分的情况没有帮助。

@markerikson我已经必须了解应用程序init上的所有reducers,以便可以调用createStore 。 我想象在下一行调用bindAllActionCreators(store.dispatch)

没错,您最终可能会引入比实际使用的代码还要多的代码。 但是,如果这是一个问题,那就不要这样。 或将您的减速器组合(减速器+动作创建者+选择器)分解为更小,更集中的捆绑包。 或仅绑定某些动作创建者。

这样做会带来一些可怕的性能损失吗? 还是以某种方式导致了通往地狱的可怕道路?

@mpoisot :并不是我能想到的任何性能问题。 但是,它确实限制了可测试性和可重用性。

正确使用connect会产生轻量级的依赖注入方法。 “普通”组件仅知道为其提供了某些功能作为道具,因此应根据需要调用该功能。 实际上,它是否是某个父组件或预绑定操作创建者直接传递的回调实际上并不在乎。 这意味着该组件可以以直接的方式重复使用,并使测试变得更加容易。 另一方面,执行类似直接导入商店的操作会导致将组件绑定到该特定商店实例和实现,这就是为什么不鼓励使用该组件的原因(根据Redux常见问题解答:http://redux.js.org/docs/faq/ StoreSetup.html#store-setup-multiple-stores)。 如果我了解您的要求是正确的,则基本上与直接导入和引用商店的情况相同。

很好的一点是,在动作创建者中部分应用分发将等同于将商店作为单例导入,这是令人皱眉的。 我试图了解原因,然后发现丹·阿布拉莫夫(Dan Abramov)曾在几个地方说过由于服务器端渲染(大多数人永远不会使用)而导致单例商店被皱眉,但奇怪的是他从未提及测试(每个人都应该这样做,或者至少对不做感到很难过)。

这让我想,您肯定可以创建一个商店单例对象,该商店的商店可以用其他商店更新以进行测试吗? 而不是直接导出商店本身,而是通过StoreSingleton.getStore()返回它,并通过StoreSingleton.setStore()更改当前商店。 因此,在测试方面,您不会受到商店的单个实例的束缚。 但是,我可以看到为什么这在线程服务器环境中不起作用。

@mpoisot您刚刚描述了提供程序/连接的作用。 ;)

通常,我有一个“哑巴”组件,有一天需要调度(或预绑定动作)。 因此,我将他包裹在连接中,或者也许将东西从连接的包含组件中传下来。 为了避免全局访问派遣,通常感觉到很多布线和传递道具。 对于mapStateToProps(),使用Provider / connect()可以显着提高性能。 对于重用哑组件,将分派逻辑提取到高阶组件绝对是有意义的。

但是我已经多次碰到这种情况,想知道为什么。 答案似乎是“这样,您就可以在某天进行服务器端渲染”。 (如果我错了,请纠正我)。

现在, connect()只是从Provider的商店为您提供了dispatch方法,但是在将来,这可能会改变。 例如,我们可能会添加额外的功能,例如与开发工具集成,以告诉您哪些React组件是触发操作的源。 否则,有人可能会制作一个通过另一种方式来增强商店的组件,方法是将商店置于上下文中,以某种方式对其进行增强,然后将该增强的商店传递给组件树。 如果您将动作创建者绑定到单例商店,则可能会调用错误的dispatch

是的,我见过的一些“组件/封装状态”实验正是使用这种方法。 关于这个想法的妙处是,其他组件不需要知道任何更改,因为包装器组件仍然只抓this.context.store并根据需要使用其dispatch

我一直在这方面-

在我的主要应用程序中,我们将商店视为单例,并使用全局可用的getStore()函数。 我们不使用服务器端渲染。 我们仍将Providerconnect用于mapStateToProps

另一方面,我构建了一个实验性应用程序,在其中将商店(如提到的@jimbolla@markerikson )包装在组件层次结构中的各个位置,并且dispatchgetState都可以在整个应用中进行更改,这意味着它们必须在整个应用中进行连接(通过contextprops ),并且不能为单例。

根据您要完成的工作,我认为单例存储的东西是可行的,但就我个人而言,我正在慢慢地摆脱它。

是的您当然可以将商店视为可访问的单例,但是它确实限制了您,它不被认为是惯用的,而且我认为这样做没有任何真正的优势。

谢谢,很好的反馈。 有人可以张贴一个链接来炫耀一些商店包装吗?

@mpoisot

这是Dan的评论之一,它说明了包装dispatch可能是有用的:

https://github.com/reactjs/redux/issues/822#issuecomment -145271384

您可能需要阅读整个主题,才能更好地理解动机是什么。

特别要注意dispatch的包装方式(我已将其突出显示):

wrappeddispatch

很抱歉因为我面临类似的困惑而劫持了这个旧帖子,希望在没有联系的情况下分派行动。

export default class App extends Component {
...
  componentDidMount() {
    //registering event listener
    BackgroundGeolocation.on('location', this.onLocation, this.onError);
  }

  onLocation(location) {
   //wishing to dispatch an action to update variable in store
  }

  render() {
    return (
      <Provider store={store}>
        <AlertProvider>
          <MainNavigator screenProps={{ isConnected: this.state.isConnected }} />
        </AlertProvider>
      </Provider>
    );
  }
}

据我了解,由于我们只是在配置存储并将其传递到Provider ,因此我可能无法连接到此组件中的存储。 我如何在onLocation事件中调度动作?

@isaaclem :嗯,在这种情况下,您对商店有一个引用,因此您可以直接调用store.dispatch(someAction)

另一个选择是重组您的组件结构,以便某些组件_inside_ <Provider>进行后台地理定位行为,并且也可以将其连接。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

timdorr picture timdorr  ·  3评论

rui-ktei picture rui-ktei  ·  3评论

jbri7357 picture jbri7357  ·  3评论

vraa picture vraa  ·  3评论

benoneal picture benoneal  ·  3评论