Повторно использовать метод из другого компонента

Я хотел бы передать оба состояния в результате метода getSettings в компоненте настроек для добавления компонента. Есть ли способ сделать это, не копируя метод в другой компонент?

Спасибо

Компонент настроек

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: []
    };
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
8
0
266
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете попробовать что-то вроде ниже, не зная, как и где вы визуализируете компонент <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 в его методе рендеринга.

В этом случае хороша компонента высокого порядка. Сначала вы создаете метод 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 Component. Вы можете вызвать в this.props.getSetting или использовать this.props. languages и this.props. currencies

import {withGetSetting} from './withGetSetting'

class Add extends React.Component {...}

export default withSetting(Add) 

О HOC можно прочитать здесь https://reactjs.org/docs/higher-order-components.html

@SungKim, твой ответ и этот чертовски полезны! Большое спасибо. И я говорил, что, может быть, Redux - подходящий способ! Я должен больше учиться.

devserkan 27.07.2018 04:09

Я могу придумать два способа поделиться своими состояниями в Settings.

  1. Использование шаблона Ребенок как функция / опора для рендеринга.
  2. Используя новый React Context API.

Ребенок как функция / опора для рендеринга

вы можете просто передать состояние в this.props.children или this.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

Ответ принят как подходящий

Извините за мою страстную мольбу, но из любви ко всему священному, пожалуйста, не используйте абстракции компонентов более высокого порядка, рендеринг реквизитов и т. д. Это простая проблема, которая заслуживает простого решения. Никакой магии не требуется. Никаких эзотерических знаний React не требуется.

  1. Выполните рефакторинг функции getSettings вне компонентов.
  2. Заставить функцию getSettings принимать параметр компонента.
  3. Внутри функции getSettings замените любое использование this на параметр component.
  4. Импортируйте функцию getSettings в любой компонент, который будет ее использовать.
  5. Передайте экземпляр компонента в эту функцию. Например. getSettings (это)
  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));

@LambrosSymeonaki Simple - лучшее. Люблю это ?

dance2die 27.07.2018 20:39

Другие вопросы по теме