【问题标题】:How can I use Redux `connect` from inside a React component?如何从 React 组件内部使用 Redux `connect`?
【发布时间】:2021-10-21 10:50:23
【问题描述】:

让我们规定一下,我灵魂深处的高深劝告促使我构建了一个 React 组件,该组件包装了对 Redux connect 的调用,如下所示:

// ReduxWrapper.tsx

import React from 'react'
import {connect, useStore} from 'react-redux'

interface SomeOtherComponentProps {
    foo?: string,
    bar?: string
}

function SomeOtherComponent({foo, bar}: SomeOtherComponentProps) {
    return (
        <div>
            This is a component with foo={foo} and bar={bar}!
        </div>
    )
}

export default function ReduxWrapper(
    child_props: SomeOtherComponentProps
): React.ReactElement {
    const store = useStore()
    const mapStateToProps = (state: {}) => ({
        // @ts-ignore
        foo: state.foo
    });

    return connect(
        mapStateToProps, {}
    )(SomeOtherComponent)(child_props) as React.ReactElement<any, string | React.JSXElementConstructor<any>>
}
// App.tsx

const store = makeStoreCorrectly()

...

return (
   <Provider store={store}>
       <ReduxWrapper bar="baz" />
   </Provider>
)

出于这个问题的目的,我们不要问为什么我想这样做,或者这是否是个好主意。可以做到吗?我不知道如何在此处正常调用connect。 (在目前的形式中,我得到了一个TypeError: Object(...)(...)(...) is not a function。)

【问题讨论】:

  • 这显然是一个xy problem,你知道的:let's not ask why I want to do this 你可能想看看自定义钩子。

标签: reactjs typescript redux react-functional-component


【解决方案1】:

请记住,connect 实际上并不返回一个 React 元素,而是一个组件。

export default function ReduxWrapper(props) {
  // try to keep the same identity of `ReduxComponent` across re-renders
  // every time this change, the component re-mount.
  const ReduxComponent = React.useMemo(
    () => connect(mapStateToProps, mapDispatchToProps)(SomeOtherComponent),
    []
  );
  
  return React.createElement(ReduxComponent, props);
}

【讨论】:

    【解决方案2】:

    出于这个问题的目的,我们不要问我为什么要这样做,或者这是否是个好主意。

    非常清楚:不,你不应该这样做,这不是一个好主意!

    问题是每次调用connect 都会创建一个新的组件类型,而you should never create a new component type while rendering!。与上次渲染相比,每次 React 在同一位置看到新的组件类型时,它都会销毁并丢弃该组件实例由该子节点渲染的所有 DOM 节点。

    唯一你甚至可以假设性地摆脱这个并让它“工作”的方法是记住组件的创建:

    const MyConnectedComponent = useMemo(() => {
      return connect()(MyComponent);
    }, [])
    
    return <MyConnectedComponent />
    

    但这仍然不是一个好主意。

    此外,如果您有可用的钩子 API,我不确定您为什么还要考虑使用 connect 做这样的事情。

    如果您能提供更多细节,我或许可以提供更具体的建议。

    【讨论】:

    • (上下文:这个答案是由实现连接和钩子的人提供给你的。认真对待)
    猜你喜欢
    • 2018-09-09
    • 2016-05-28
    • 2021-02-24
    • 2018-06-06
    • 2017-03-11
    • 2019-01-10
    • 2017-01-12
    • 2019-05-09
    • 1970-01-01
    相关资源
    最近更新 更多