重用另一个组件中的方法

时间:2018-07-27 01:04:05

标签: reactjs

我想将这两种状态作为Settings组件中的getSettings方法的结果传递给Add组件。有没有办法将方法复制到其他组件?

谢谢

设置组件

export class Settings extends Component {
    constructor(props) {
        super(props);

        this.state = {
         languages: [],
         currencies: []
        };
    }

    getSettings() {
        fetch('/settings', {
            method: 'get',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            }
        })
        .then( ... )
        .then(json => {
            this.setState({
                currencies: json.currencies,
                languages: json.languages
            });
        })
    }
}

添加组件

export class Add extends Component {
    displayName = Add.name

constructor(props) {
    super(props);

    this.state = {
    languages: [],
    currencies: []
    };
}

4 个答案:

答案 0 :(得分:5)

我可以想到两种在Settings中共享状态的方式。

  1. 使用Child as Function/Render Prop模式。
  2. 使用新的React Context API

子级作为功能/渲染属性

您只需将状态传递到this.props.childrenthis.props.render

class Settings extends Component {
  state = {
    languages: [],
    currencies: []
  };
  getSettings = () => {
    // fetch('/settings', {
    //     method: 'get',
    //     headers: {
    //         'Accept': 'application/json',
    //         'Content-Type': 'application/json'
    //     }
    // })
    // .then( ... )
    // .then(json => {
    //     this.setState({
    //         currencies: json.currencies,
    //         languages: json.languages
    //     });
    // })
    this.setState({
      currencies: ["Dollar", "Euro", "Won"],
      languages: ["English", "French", "Korean"]
    });
  };

  componentDidMount() {
    this.getSettings();
  }

  render() {
    return <div>{this.props.children(this.state)}</div>;
  }
}

并像这样使用它。

const renderComponents = (currencies, languages) => {
  const currencyItems = currencies.map(currency => (
    <li key={currency}>{currency}</li>
  ));
  const languageItems = languages.map(language => (
    <li key={language}>{language}</li>
  ));
  return (
    <div>
      <h3>currencies</h3>
      <ul>{currencyItems}</ul>
      <hr />
      <h3>languages</h3>
      <ul>{languageItems}</ul>
    </div>
  );
};

const AppChildAsFunction = () => (
  <div>
    <h2>Using Child as Function</h2>
    <Settings>
      {({ currencies, languages }) => renderComponents(currencies, languages)}
    </Settings>
  </div>
);

使用新的React Context API

创建和导出新的设置提供程序以及使用者

SettingsContext.js

import React, { Component } from "react";

const defaultValue = {
  currencies: ["Dollar", "Euro", "Won"],
  languages: ["English", "French", "Korean"]
};
const { Provider, Consumer: SettingsConsumer } = React.createContext(
  defaultValue
);

class SettingsProvider extends Component {
  state = {
    languages: [],
    currencies: []
  };
  render() {
    return <Provider value={this.state}>{this.props.children}</Provider>;
  }
}

export { SettingsProvider, SettingsConsumer };

用法也差不多

App.js

import { SettingsProvider, SettingsConsumer } from "./SettingsContext";
...
const AppWithContext = () => (
  <div>
    <h2>Using Context API</h2>
    <SettingsConsumer>
      {({ currencies, languages }) => renderComponents(currencies, languages)}
    </SettingsConsumer>
  </div>
);

您可以选择适合自己口味的任何一种。

在CodeSandBox上进行演示
Edit so.answer.51549396

enter image description here

答案 1 :(得分:4)

高阶分量对于这种情况很有用。首先,您创建方法withSetting

export const withSetting = (Component) => class extends Component {
  constructor(props) {
      super(props);
      this.state = {
       languages: [],
       currencies: []
      };
  }
  getSettings() {
      fetch('/settings', {
          method: 'get',
          headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/json'
          }
      })
      .then( ...)
      .then(json => {
          this.setState({
              currencies: json.currencies,
              languages: json.languages
          });
      })
  }
  render() {
    return <Component getSetting={this.getSetting} {...this.state} />
  }
}

Add组件中。您可以致电this.props.getSetting或使用this.props. languagesthis.props. currencies

import {withGetSetting} from './withGetSetting'

class Add extends React.Component {...}

export default withSetting(Add) 

您可以在https://reactjs.org/docs/higher-order-components.html

处了解有关HOC的信息。

答案 2 :(得分:3)

请原谅我慷慨激昂的恳求,但出于对所有神圣事物的热爱,请不要使用高阶组件抽象,渲染道具等。这是一个简单的问题,值得一个简单的解决方案。不需要魔术。不需要深奥的React知识。

  1. 在组件之外重构getSettings函数。
  2. 使getSettings函数接受组件参数。
  3. 在getSettings函数中,将所有对“ this”的使用替换为“ component”参数
  4. 将getSettings函数导入将使用该函数的任何组件中。
  5. 将组件实例传递给此函数。例如。 getSettings(this)
  6. 恭喜,您现在拥有一个可重用且可独立测试的功能,任何组件(或与此相关的任何其他组件)都可以根据需要使用。

    const getSettings = component => () => {
      // Do your fetch here, and in your last
      // .then(), just use 'component.setState'
      // instead of 'this.setState'
    
      // Simulate async
      setTimeout(() => {
        component.setState({
          name: component.name,
          currencies: "whatever",
          languages: "yep"
        });
      }, 1000);
    };
    
    export default getSettings;
    

就这么简单。

请参见https://codesandbox.io/s/mjmpw5k08y

编辑

事后看来,您可能会接受回调函数而不是组件,或返回诺言。这些中的任何一个都将使其与React组件的耦合减少。未经测试的代码如下...

带有回调

const getSettings = callback => {
  // Simulate async
  setTimeout(() => {
      callback({
      name: component.name,
      currencies: "whatever",
      languages: "yep"
    });
  }, 1000);
};

用法

getSettings(this.setState.bind(this));

带有回调

const getSettings = () => window.fetch
    .then(res => res.json());

用法

getSettings().then(this.setState.bind(this));

答案 3 :(得分:1)

您可以尝试以下类似方法,不确定如何渲染<Add>组件的方式和位置:

export class Settings extends Component {
  constructor(props) {
    super(props);

    this.state = {
      languages: [],
      currencies: []
    };
  }

  getSettings() {
    return fetch('/settings', {
        method: 'get',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        }
      })
      .then(...)
      .then(json => {
        this.setState({
          currencies: json.currencies,
          languages: json.languages
        });
      })
  }

  render() {
    return (
        { this.getSettings() && <Add { ...this.state}/> }
      );
    }
  }

在您的<Add>组件中,只需使用其渲染方法从props中读取即可。