Как я могу разделить функцию в компоненте с подключением к реактору с другими компонентами? - PullRequest
2 голосов
/ 20 февраля 2020

У меня есть функция (инициализация), определенная в компоненте React, которая отправляет кучу избыточных действий.

import { setData, doThing, doSomethingElse } from "redux/actions";
import { fetchData } from "services/api";
import { connect } from "react-redux";

class Basic extends Component {
  initialize = () => {
    const { setData, doThing, doSomethingElse } = this.props;
    if (someLogic) {
      doThing();
    } else {
      doSomethingElse();
    }
    fetchData.then(data => setData(data));
  };

  componentDidMount() {
    this.initialize();
  }

  render() {
    const { loading } = this.props;
    if (loading) {
      return <div>Loading...</div>;
    }
    return <div>Content</div>;
  }
}

const mapStateToProps = ({ state }) => ({
  loading: state.loading
});

const mapDispatchToProps = {
  setData,
  doThing,
  doSomethingElse
};

export default connect(mapStateToProps, mapDispatchToProps)(Basic);

Это прекрасно работает в этом сценарии, но, поскольку я разрабатываю свое приложение, я понимаю, что может потребоваться вызвать 'initialize' и в некоторых других компонентах. Что было бы для меня лучшим способом извлечь эту функцию для повторного использования в других компонентах?

Я испытываю желание извлечь ее в вспомогательную функцию, например:

import store from "redux/store";

export function initializeHelper() {
  if (someLogic) {
    store.dispatch(doThing());
  } else {
    store.dispatch(doSomethingElse());
  }
  fetchData.then(data => store.dispatch(setData(data)));
}

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

Еще одна вещь, которую я пробовал, - это использование компонента рендеринга, который просто передает функцию следующим образом:

class Initialize extends Component {
  initialize = () => {
    const { setData, doThing, doSomethingElse } = this.props;
    if (someLogic) {
      doThing();
    } else {
      doSomethingElse();
    }
    fetchData.then(data => setData(data));
  };

  render() {
    return this.props.children(this.initialize)
  }
}

// Wrap any component to pass the function as a prop

<Initialize>
  {initialize => <OtherComponent initialize={initialize} />}
</Initialize>

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

Есть ли лучший способ go об этом?

Примечание: я еще не планирую использовать ловушки React в моем текущем проекте .

Ответы [ 2 ]

0 голосов
/ 21 февраля 2020

Это хороший вариант использования HO C. У вас есть повторяющийся шаблон инициализации данных. Этот код может быть извлечен в HO C (Компонент высшего порядка), функция, которая будет принимать компонент, который будет представлен в одном из своих аргументов. Этот HO C выполнит инициализацию для вашего компонента и отобразит компонент с подписанными данными в качестве реквизита для компонента. (В случае, если вам нужно. Вы не использовали его в своем примере)

HO C будет подключено к резервной копии, и дочерний компонент не должен быть подключен

Давайте посмотрим на код.

import { setData, doThing, doSomethingElse } from "redux/actions";
import { fetchData } from "services/api";
import { connect } from "react-redux";

const InitializeOnMount = (Component) => {

   class InitializerComponent extends Component {

     initialize = () => {
      const { setData, doThing, doSomethingElse } = this.props;
      if (someLogic) {
        doThing();
      } else {
        doSomethingElse();
      }
      fetchData.then(data => setData(data));
     };

     componentDidMount() {
       this.initialize();
     }

     render() {
       const { loading } = this.props;
       if (loading) {
         return <div>Loading...</div>;
       }
       return <Component />;
     }
   }

   const mapStateToProps = ({ state }) => ({
     loading: state.loading
   });

   const mapDispatchToProps = {
     setData,
     doThing,
     doSomethingElse
   };

   return connect(mapStateToProps, mapDispatchToProps)(InitializerComponent);
};

export {InitializeOnMount};
0 голосов
/ 20 февраля 2020

Взгляните на Компоненты высшего порядка . Согласно документам: «Компонент высшего порядка (HO C) - это продвинутая техника в React для повторного использования logi c компонента, которая является именно тем, что вы пытаетесь сделать.

A Higher Order Компонент, который будет иметь желаемое поведение между вашими компонентами, может выглядеть следующим образом:

const withInit = (componentToWrap) => (props) => { 
  useEffect(() => { 
    // something to execute on mount
  },[])

  return <componentToWrap {...props}/>
}

Документы предоставляют способы достижения этого и с классами. Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...