在React中分享组件之间功能的正确方法

时间:2015-10-01 13:22:38

标签: reactjs

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

我可以在顶级组件中定义它,然后将其作为道具传递下去。但这并不是很正确。它更像是一个库函数而不是一个prop。 (在我看来)。

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

8 个答案:

答案 0 :(得分:22)

如果您使用类似browserify的内容,则可以使用外部文件,即util.js导出一些实用程序函数。

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

exports.doSomething = doSomething;

然后根据需要要求

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

答案 1 :(得分:7)

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

解决方案1:使用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)

<强>组件/ 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;

答案 2 :(得分:7)

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

这被认为是React的一个好习惯。 You can find out how to do so in detail here.

答案 3 :(得分:6)

具有最新JavaScript SE6语法的Utils.js

使用多种功能创建Utils.js文件

import React, {Component} from 'react';

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>

答案 4 :(得分:3)

听起来像是一个实用程序函数,在这种情况下为什么不把它放在一个单独的静态实用程序模块中?

否则,如果使用像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 +中做到这一点(在这种情况下我不会看到好处) )。

答案 5 :(得分:3)

这取决于组件的逻辑之间有多少关联。

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

相对相关的组件可以使用./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

实用程序类型的组件可以在./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"));
    }
}

答案 6 :(得分:2)

答案 7 :(得分:0)

如果要在辅助函数中操作状态,请遵循以下步骤:

  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> }