Загрузка экрана с помощью React + Redux - PullRequest
0 голосов
/ 12 января 2020

Прямо сейчас у меня есть приложение реакции, использующее редукс. Я создал компонент, который работает как форма для создания клиентов. Как это:

import { createCustomer } from "../../actions";

class CustomerCreate extends React.Component {

  state = {
    submitting: false
  }

  componentWillReceiveProps(nextProps) {
    this.setState({ submitting: false });
  }

  submitData = (data) => {
    this.setState({ submitting: true });
    this.props.createCustomer(data);
  };

  render() {
    return (
      <React.Fragment>
        {this.state.submitting ? <LoadingScreen /> : null}
        {this.props.error ? <ErrorMessage message={this.props.error}/> : null}
        <FormContainer
        ...
        />
      </React.Fragment>
    );
  }
}

const mapStateToProps = ({ customerData }) => {
  return {
    error: customerData.error
  };
};

export default connect(mapStateToProps, { createCustomer })(
  CustomerCreate
);

Это работает "отлично". В основном componentWillReceiveProps будет вызываться каждый раз, когда что-то происходит (ошибка, хорошо), поэтому я буду знать, когда снимать загрузочный экран. Проблема заключается в том, что componentWillReceiveProps выдает предупреждение (говорящее, что его не следует использовать), и на основе избыточной документации это помечается как анти-шаблон.

Я знаю, что одно решение может быть не используя редукса здесь. Изменение submitData с помощью вызова axions и размещение setState там. Но я использовал его так, потому что одно из сообщений об ошибке может быть: SESSION EXPIRED или INVALID JWT TOKEN , поэтому мне нужно повторно отправить веб-страницу на экран входа в систему.

Другой способ, который я могу себе представить, - это вызов в действии диспетчеризации для установки состояния isSubmitting. Примерно так:

export const createCustomer = (data) => {
  /* IS THIS VALID? */
  dispatch({ type: CUSTOMER_SUBMITTING });
  return async function (dispatch) {
    try {
      const response = await services.post("/api/customer", data, buildHeader());
      dispatch({ type: CUSTOMER_CREATED, payload: response.data });
    } catch (err) {
      dispatch({ type: CUSTOMER_ERROR, payload: err });
    }
  };
};

И вместо использования state.isSubmitting я буду использовать props.isSubmitting . Но я не уверен, что вызов двух диспатов, как этот, является действительным / правильным.

Итак, мой вопрос: Как я могу реализовать состояние / реквизиты, которые установлены в true, когда я отправляю и устанавливается на false, когда вызов ax ios завершен (из-за какой-то ошибки или просто ОК).

Ответы [ 2 ]

0 голосов
/ 25 января 2020

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

https://medium.com/stashaway-engineering/react-redux-tips-better-way-to-handle-loading-flags-in-your-reducers-afda42a804c6

Я создал загрузочный редуктор следующим образом:

const INITIAL_STATE = {
}

const loadingReducer = (state = INITIAL_STATE, action) => {
    const { type } = action;
    const matches = /(.*)_(DELETE|REQUEST|SUCCESS|FAILURE)/.exec(type);

    // not a *_REQUEST / *_SUCCESS /  *_FAILURE actions, so we ignore them
    if (!matches) return state;
    const [, requestName, requestState] = matches;
    return {
        ...state,
        // Store whether a request is happening at the moment or not
        // e.g. will be true when receiving GET_TODOS_REQUEST
        //      and false when receiving GET_TODOS_SUCCESS / GET_TODOS_FAILURE
        [requestName]: requestState === 'REQUEST',
        [requestName + '_DELETE']: requestState === 'DELETE',
    };
};

export default loadingReducer;

Затем создал функцию loadingSelector:

import _ from 'lodash';

export const createLoadingSelector = (actions) => (state) => {
    // returns true only when all actions is not loading
    return _(actions)
        .some((action) => _.get(state, action));
};

И затем создал компонент, который изменяет статус на основе этого редуктора:

class LoadingScreen extends React.Component {

    render() {
        if (!this.props.isLoading)
            return null;
        return (
            <Backdrop
                className={this.props.classes.backdrop}
                open={true}
            >
                <CircularProgress color="inherit" />
            </Backdrop>
        )
    }


}

const loadingListSelector = createLoadingSelector(['CUSTOMERS']);

const mapStateToProps = ({ loading }) => {
    return {
        isLoading: loadingListSelector(loading)
    };
};
0 голосов
/ 12 января 2020

Использовать componentDidUpdate функцию жизненного цикла. Добавьте действие успешной обработки формы и состояние в приставке и сопоставьте его с реквизитом.

import { createCustomer } from "../../actions";

class CustomerCreate extends React.Component {

  state = {
    submitting: false
  }

  componentDidUpdate(prevState, prevProps) {
    // If a new error comes in and was previously "falsey" set submitting false
    if (prevProps.error !== this.props.error && this.props.error) {
      this.setState({ submitting: false });
    }
    // Similar check for form success
  }

  submitData = (data) => {
    this.setState({ submitting: true });
    this.props.createCustomer(data);
  };

  render() {
    return (
      <React.Fragment>
        {this.state.submitting ? <LoadingScreen /> : null}
        {this.props.error ? <ErrorMessage message={this.props.error}/> : null}
        <FormContainer
        ...
        />
      </React.Fragment>
    );
  }
}

const mapStateToProps = ({ customerData }) => {
  return {
    error: customerData.error,
    success: /* some success value from redux */
  };
};

export default connect(mapStateToProps, { createCustomer })(
  CustomerCreate
);

Или в качестве функционального компонента используйте хуки состояния и эффекта:

import { createCustomer } from "../../actions";

const CustomerCreate ({ createCustomer, error, success }) => {

  const [submitting, setSubmitting] = useState(false);

  useEffect(() => {
    if (error || success) setSubmitting(false);
  }, [error, success]);

  submitData = (data) => {
    setSubmitting(true);
    createCustomer(data);
  };

  return (
    <React.Fragment>
      {submitting ? <LoadingScreen /> : null}
      {error ? <ErrorMessage message={error}/> : null}
      <FormContainer
        ...
      />
    </React.Fragment>
  );
}

const mapStateToProps = ({ customerData }) => ({
  error: customerData.error,
  success: /* some success value from redux */
});

export default connect(mapStateToProps, { createCustomer })(
  CustomerCreate
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...