【问题标题】:Correct way to share functions between components in React在 React 中的组件之间共享功能的正确方法
【发布时间】:2015-10-01 13:22:37
【问题描述】:

我有多个组件都需要做同样的事情。 (一个简单的函数,它映射它们的子组件并对每个子组件做一些事情)。目前,我正在每个组件中定义此方法。但我只想定义一次。

我可以在顶级组件中定义它,然后将其作为道具传递。但这感觉不太对劲。它更像是一个库函数而不是一个道具。 (在我看来)。

这样做的正确方法是什么?

【问题讨论】:

  • 查看this link。或者在 google 中搜索“mixins”和“HOC”。

标签: reactjs


【解决方案1】:

具有最新 Javascript ES6 语法的 Utils.js

像这样创建Utils.js文件,具有多种功能等

const someCommonValues = ['common', 'values'];

export const doSomethingWithInput = (theInput) => {
   //Do something with the input
   return theInput;
};

export const justAnAlert = () => {
   alert('hello');
};

然后在您想要使用 util 函数的组件中,导入所需的特定函数。您不必导入所有内容

import {doSomethingWithInput, justAnAlert} from './path/to/utils.js/file'

然后像这样在组件中使用这些函数:

justAnAlert();
<p>{doSomethingWithInput('hello')}</p>

【讨论】:

  • 导入行末尾的/file 是做什么用的?
  • @alex 这只是一个例子。把你的 util.js 的相对路径放在那里
  • 最好删除/file,您的示例使用Utils.js,所以这正是应该在那里显示的内容
  • 这是分享实用工具的最佳解决方案之一,谢谢!!!
  • 最好放在/src文件夹还是/components文件夹中?
【解决方案2】:

如果你使用browserify 之类的东西,那么你可以拥有一个外部文件,即 util.js,它可以导出一些实用功能。

var doSomething = function(num) {
 return num + 1;
}

exports.doSomething = doSomething;

然后根据需要要求它

var doSomething = require('./util.js').doSomething;

【讨论】:

  • @AnkitSinghaniya 这取决于,您使用什么来管理应用程序的前端状态?
  • 我正在使用反应状态。
  • 为什么我得到 'doSomething' 没有定义没有任何想法?
【解决方案3】:

如果您想在辅助函数中操作状态,请按照以下步骤操作:

  1. 创建一个 Helpers.js 文件:

    export function myFunc(){ return this.state.name; //define it according to your needs }

  2. 在组件文件中导入辅助函数:

    import {myFunc} from 'path-to/Helpers.js'

  3. 在您的构造函数中将该辅助函数添加到类中

    constructor(){ this.myFunc = myFunc.bind(this) }

  4. 在你的渲染函数中使用它:

    render(){ <div>{this.myFunc()}</div> }

【讨论】:

    【解决方案4】:

    以下是一些示例,说明如何在 React 组件 (App) 中重用函数 (FetchUtil.handleError)。

    解决方案一:使用 CommonJS 模块语法

    module.exports = {
      handleError: function(response) {
        if (!response.ok) throw new Error(response.statusText);
        return response;
      },
    };
    

    解决方案 2:使用“createClass”(React v16)

    util/FetchUtil.js

    const createReactClass = require('create-react-class');
    
    const FetchUtil = createReactClass({
      statics: {
        handleError: function(response) {
          if (!response.ok) throw new Error(response.statusText);
          return response;
        },
      },
      render() {
      },
    });
    
    export default FetchUtil;
    

    注意:如果您使用的是 React v15.4(或更低版本),您需要导入 createClass,如下所示:

    import React from 'react';
    const FetchUtil = React.createClass({});
    

    来源:https://reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactcreateclass

    组件(复用 FetchUtil)

    components/App.jsx

    import Categories from './Categories.jsx';
    import FetchUtil from '../utils/FetchUtil';
    import Grid from 'material-ui/Grid';
    import React from 'react';
    
    class App extends React.Component {
      constructor(props) {
        super(props);
        this.state = {categories: []};
      }
    
      componentWillMount() {
        window
          .fetch('/rest/service/v1/categories')
          .then(FetchUtil.handleError)
          .then(response => response.json())
          .then(categories => this.setState({...this.state, categories}));
      }
    
      render() {
        return (
          <Grid container={true} spacing={16}>
            <Grid item={true} xs={12}>
              <Categories categories={this.state.categories} />
            </Grid>
          </Grid>
        );
      }
    }
    
    export default App;
    

    【讨论】:

    • 方案一挺好的,我在ExpressJS中也用过
    【解决方案5】:

    除了创建 util 文件之外,另一个可靠的选择是使用更高阶的组件来创建 withComponentMapper() 包装器。该组件将接收一个组件作为参数并将其返回,并将 componentMapper() 函数作为 prop 向下传递。

    这在 React 中被认为是一个很好的实践。 You can find out how to do so in detail here.

    【讨论】:

    • 我很好奇为什么 React 不鼓励与组件模式相似的组件继承?
    • @Wor 使用继承意味着两个组件
    【解决方案6】:

    我将在下面展示两种样式,您需要根据组件的逻辑相互关联程度进行选择。

    样式 1 - 相对相关的组件可以在./components/App.js...中使用回调引用创建,就像这样,在./components/App.js...

    <SomeItem
        ref={(instance) => {this.childA = instance}}
    />
    
    <SomeOtherItem
        ref={(instance) => {this.childB = instance}}
    />
    

    然后你就可以像这样使用他们之间的共享功能了...

    this.childA.investigateComponent(this.childB);  // call childA function with childB as arg
    this.childB.makeNotesOnComponent(this.childA);  // call childB function with childA as arg
    

    样式 2 - Util 类型的组件可以像这样创建,在./utils/time.js...

    export const getTimeDifference = function (start, end) {
        // return difference between start and end
    }
    

    然后它们可以像这样使用,在./components/App.js...

    import React from 'react';
    import {getTimeDifference} from './utils/time.js';
    
    export default class App extends React.Component {
        someFunction() {
            console.log(getTimeDifference("19:00:00", "20:00:00"));
        }
    }
    

    使用哪个?

    如果逻辑是相对相关(它们只能在同一个应用中一起使用),那么您应该在组件之间共享状态。但如果你的逻辑是远相关(即数学工具、文本格式化工具),那么你应该制作和导入工具类函数。

    【讨论】:

      【解决方案7】:

      听起来像一个实用函数,那么为什么不把它放在一个单独的静态实用模块中呢?

      否则如果使用像 Babel 这样的编译器,你可以使用 es7 的静态方法:

      class MyComponent extends React.Component {
        static someMethod() { ...
      

      否则,如果您使用 React.createClass,您可以使用 statics 对象:

      var MyComponent = React.createClass({
        statics: {
          customMethod: function(foo) {
            return foo === 'bar';
          }
        }
      

      但是我不建议这些选项,为实用方法包含组件是没有意义的。

      此外,您不应该将方法作为道具传递给所有组件,这会使它们紧密耦合并使重构更加痛苦。我建议使用普通的旧实用程序模块。

      另一种选择是使用 mixin 来扩展类,但我不建议这样做,因为你不能在 es6+ 中这样做(而且我看不到这种情况下的好处)。

      【讨论】:

      • 关于 mixins 的信息很有用。在这种情况下,我想有条件地使用该函数,而不是在生命周期事件中自动发生某些事情。所以。正如你所说,一个普通的旧实用程序函数是要走的路。
      • 注意:React.createClass 自 React 15.5.0 起已弃用。 create-react-app 建议使用 npm 模块 create-react-class
      • 我希望做与 OP 相同的事情,但我在这里有点困惑。您不推荐您列出的任何选项。你推荐什么
      • 我会简单地为函数创建一个文件,例如doSomething.js,或具有多个类似“实用程序”功能的文件,例如utils.js 并在需要用到的地方导入那些函数
      【解决方案8】:

      【讨论】:

      • 我同意 mixin 是一个比仅仅导出一个通用函数更好的解决方案。
      • @TaoHuang 需要考虑的一些事情,1.Mixins 不是面向未来的,在现代应用程序中将越来越少地使用,2.使用导出的函数使您的代码框架不可知 - 您可以轻松使用这些在任何其他 js 项目上运行。另外请阅读这篇关于为什么不使用 Mixins 的帖子 --> facebook.github.io/react/blog/2016/07/13/…
      • mixin 可以访问和修改状态,而 trait 不能,并且由于 OP 说他们想要将某些东西视为函数库,因此 mixin 不是正确的解决方案。
      • 要更新这个,使用高阶函数。 facebook.github.io/react/docs/higher-order-components.html
      • 第一个链接失效
      猜你喜欢
      • 1970-01-01
      • 2022-10-06
      • 2020-09-23
      • 1970-01-01
      • 2021-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多