从其他组件重用方法

Dam*_*ian 8 reactjs

我想将两个状态作为设置组件中的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
            });
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

添加组件

export class Add extends Component {
    displayName = Add.name

constructor(props) {
    super(props);

    this.state = {
    languages: [],
    currencies: []
    };
}
Run Code Online (Sandbox Code Playgroud)

dan*_*die 5

我可以想到两种方式,你可以分享你的状态Settings.

  1. 使用Child作为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>;
  }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它.

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>
);
Run Code Online (Sandbox Code Playgroud)

使用新的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 };
Run Code Online (Sandbox Code Playgroud)

用法大致相同

App.js

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

您可以选择适合您口味的任何一种.

CodeSandBox上的工作演示.
编辑so.answer.51549396

在此输入图像描述


小智 2

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

  1. 从组件中重构 getSettings 函数。
  2. 使 getSettings 函数接受组件参数。
  3. 在 getSettings 函数中,将所有使用的 'this' 替换为 'component' 参数
  4. 将 getSettings 函数导入到任何将使用它的组件中。
  5. 将组件实例传递给此函数。例如。获取设置(这个)
  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;
    
    Run Code Online (Sandbox Code Playgroud)

就这么简单。

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

编辑

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

带回调

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

用法

getSettings(this.setState.bind(this));
Run Code Online (Sandbox Code Playgroud)

带回调

const getSettings = () => window.fetch
    .then(res => res.json());
Run Code Online (Sandbox Code Playgroud)

用法

getSettings().then(this.setState.bind(this));
Run Code Online (Sandbox Code Playgroud)