【问题标题】:How can I share a function in a react-redux connected component with other components?如何与其他组件共享 react-redux 连接组件中的功能?
【发布时间】:2020-02-20 03:59:47
【问题描述】:

我在 React 组件中定义了一个函数(初始化),它调度了一堆 redux 操作。

import { setData, doThing, doSomethingElse } from "redux/actions";
import { fetchData } from "services/api";
import { connect } from "react-redux";

class Basic extends Component {
  initialize = () => {
    const { setData, doThing, doSomethingElse } = this.props;
    if (someLogic) {
      doThing();
    } else {
      doSomethingElse();
    }
    fetchData.then(data => setData(data));
  };

  componentDidMount() {
    this.initialize();
  }

  render() {
    const { loading } = this.props;
    if (loading) {
      return <div>Loading...</div>;
    }
    return <div>Content</div>;
  }
}

const mapStateToProps = ({ state }) => ({
  loading: state.loading
});

const mapDispatchToProps = {
  setData,
  doThing,
  doSomethingElse
};

export default connect(mapStateToProps, mapDispatchToProps)(Basic);

这在这种情况下工作得很好,但是当我开发我的应用程序时,我意识到我可能还想在其他几个组件中调用“初始化”。对我来说,提取此函数以便在其他组件中重用的最佳方法是什么?

我很想将它提取到这样的辅助函数中:

import store from "redux/store";

export function initializeHelper() {
  if (someLogic) {
    store.dispatch(doThing());
  } else {
    store.dispatch(doSomethingElse());
  }
  fetchData.then(data => store.dispatch(setData(data)));
}

它确实有效,因为我在辅助函数中导入的商店与我的 React 应用程序中提供的商店相同。但是,这样直接调用商店感觉不对。

我尝试过的另一件事是使用渲染道具组件,它只传递函数如下:

class Initialize extends Component {
  initialize = () => {
    const { setData, doThing, doSomethingElse } = this.props;
    if (someLogic) {
      doThing();
    } else {
      doSomethingElse();
    }
    fetchData.then(data => setData(data));
  };

  render() {
    return this.props.children(this.initialize)
  }
}

// Wrap any component to pass the function as a prop

<Initialize>
  {initialize => <OtherComponent initialize={initialize} />}
</Initialize>

但这也感觉像是对渲染道具模式的错误使用,因为渲染道具不共享任何状态。它只是共享一个主要调度 redux 操作的函数。

有没有更好的方法来解决这个问题?

注意:我还没有计划在我当前的项目中使用 React 钩子。

【问题讨论】:

  • 我不确定这是否是最佳做法,但我有一个方法here
  • 外部辅助函数调用store.dispatch方法没有问题。这是一种完全有效的方法,可能是最简单/最干净的方法
  • 使它成为一个自定义钩子。仅适用于 FC 或将其放入中间件中。
  • @keikai 你能解释一下你的方法/代码吗?我对 TypeScript 不太熟悉。

标签: javascript reactjs redux react-redux


【解决方案1】:

看看Higher Order Components。根据文档:“高阶组件 (HOC) 是 React 中用于重用组件逻辑的高级技术”,这正是您想要做的。

将在您的组件之间共享所需行为的高阶组件可能如下所示:

const withInit = (componentToWrap) => (props) => { 
  useEffect(() => { 
    // something to execute on mount
  },[])

  return <componentToWrap {...props}/>
}

文档也提供了通过类实现此目的的方法。希望这会有所帮助!

【讨论】:

  • 在这种情况下使用 HOC 或渲染道具的问题是,没有与子组件共享特定于反应的逻辑。它只是将单个函数(不关心反应状态等)传递给子组件。它应该只是作为辅助函数导入,但正如我在帖子中提到的,我不确定是否建议直接使用 store.dispatch()。
  • HOC 不一定要执行任何特定于 react 的代码,它们的主要目标之一是代码重用......我想辅助函数方法也很好,只要你知道你是什么正在做。对此有一篇有趣的文章:daveceddia.com/access-redux-store-outside-react.
【解决方案2】:

这是HOC 的一个很好的用例。您有初始化数据的重复模式。 这种和平的代码可以在 HOC(高阶组件)中提取出来,该函数将在其参数之一中呈现组件。 这个 HOC 将为你的组件做初始化工作,并用订阅的数据作为组件的 props 渲染组件。 (以防万一。您的示例中没有使用它)

HOC 会连接到 redux,子组件不需要连接

让我们看看代码。

import { setData, doThing, doSomethingElse } from "redux/actions";
import { fetchData } from "services/api";
import { connect } from "react-redux";

const InitializeOnMount = (Component) => {

   class InitializerComponent extends Component {

     initialize = () => {
      const { setData, doThing, doSomethingElse } = this.props;
      if (someLogic) {
        doThing();
      } else {
        doSomethingElse();
      }
      fetchData.then(data => setData(data));
     };

     componentDidMount() {
       this.initialize();
     }

     render() {
       const { loading } = this.props;
       if (loading) {
         return <div>Loading...</div>;
       }
       return <Component />;
     }
   }

   const mapStateToProps = ({ state }) => ({
     loading: state.loading
   });

   const mapDispatchToProps = {
     setData,
     doThing,
     doSomethingElse
   };

   return connect(mapStateToProps, mapDispatchToProps)(InitializerComponent);
};

export {InitializeOnMount};

【讨论】:

    猜你喜欢
    • 2019-10-08
    • 2017-10-14
    • 1970-01-01
    • 1970-01-01
    • 2018-01-19
    • 2017-07-02
    • 1970-01-01
    • 2017-06-12
    • 1970-01-01
    相关资源
    最近更新 更多