ReactRouter v4 Prompt - переопределить предупреждение по умолчанию - PullRequest
0 голосов
/ 21 сентября 2018

Компонент React Router v4 <Prompt></Prompt> идеально подходит для случая защиты навигации от частично заполненной формы.

Но что, если мы хотим предоставить собственную логикувместо браузера по умолчанию alert(), который использует этот компонент?React предназначен для создания пользовательских интерфейсов, поэтому он выглядит довольно разумным вариантом использования.Копаясь в проблемах с подсказкой в ​​ github Я не нашел никого, кто спрашивал бы об этом.

Кто-нибудь знает решение для обеспечения настраиваемого поведения для оповещения?

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Компонент подсказки по умолчанию не позволяет переопределить использование window.alert ().

Вот ссылка на беседу, которая примерно так же соответствует вашим потребностям:

https://github.com/ReactTraining/react-router/issues/4635

Здесь есть несколько ключевых моментов, на которые вы можете сослаться, в основном, просто вместо того, чтобы использовать подсказку, вы можете просто создать свой собственный мод, который будет запускаться при определенных действиях пользователя.:)

Надеюсь, это поможет

0 голосов
/ 21 сентября 2018

Хотя вы можете использовать пользовательский модальный компонент, предотвращая переход между страницами по ссылкам, вы не можете отобразить пользовательский модал при попытке закрыть браузер или перезагрузить его.

Однако, если вас это устраивает, вы можете использовать history.listen и заблокировать навигацию.Я написал для него универсальный HOC, который решает этот вариант использования.

В приведенном ниже коде белые имена путей - это пути, по которым вы бы хотели, чтобы другой человек перемещался, не показывая подсказку

import React from 'react';
import { withRouter } from 'react-router';
import _ from 'lodash';

const navigationPromptFactory = ({ Prompt }) => {
    const initialState = {
        currentLocation: null,
        targetLocation: null,
        isOpen: false
    };

    class NavigationPrompt extends React.Component {
        static defaultProps = {
            when: true
        };

        state = initialState;

        componentDidMount() {
            this.block(this.props);
            window.addEventListener('beforeunload', this.onBeforeUnload);
        }

        componentWillReceiveProps(nextProps) {
            const {
                when: nextWhen,
                history: nextHistory,
                whiteListedPathnames: nextWhiteListedPaths
            } = nextProps;
            const { when, history, whiteListedPathnames } = this.props;
            if (
                when !== nextWhen ||
                !_.isEqual(nextHistory.location, history.location) ||
                !_.isEqual(whiteListedPathnames, nextWhiteListedPaths)
            ) {
                this.unblock();
                this.block(nextProps);
            }
        }

        componentWillUnmount() {
            this.unblock();
            window.removeEventListener('beforeunload', this.onBeforeUnload);
        }

        onBeforeUnload = e => {
            const { when } = this.props;

            // we can't override an onBeforeUnload dialog
            // eslint-disable-next-line
            // /205361/kak-ya-mogu-pereopredelit-dialog-onbeforeunload-i-zamenit-ego-svoim-sobstvennym

            if (when) {
                // support for custom message is no longer there
                // https://www.chromestatus.com/feature/5349061406228480
                // eslint-disable-next-line
                // https://stackoverflow.com/questions/38879742/is-it-possible-to-display-a-custom-message-in-the-beforeunload-popup

                // setting e.returnValue = "false" to show prompt, reference below
                //https://github.com/electron/electron/issues/2481
                e.returnValue = 'false';
            }
        };

        block = props => {
            const {
                history,
                when,
                whiteListedPathnames = [],
                searchQueryCheck = false
            } = props;
            this.unblock = history.block(targetLocation => {
                const hasPathnameChanged =
                    history.location.pathname !== targetLocation.pathname;
                const hasSearchQueryChanged =
                    history.location.search !== targetLocation.search;
                const hasUrlChanged = searchQueryCheck
                    ? hasPathnameChanged || hasSearchQueryChanged
                    : hasPathnameChanged;
                const isTargetWhiteListed = whiteListedPathnames.includes(
                    targetLocation.pathname
                );
                const hasChanged =
                    when && hasUrlChanged && !isTargetWhiteListed;
                if (hasChanged) {
                    this.setState({
                        currentLocation: history.location,
                        targetLocation,
                        isOpen: true
                    });
                }
                return !hasChanged;
            });
        };

        onConfirm = () => {
            const { history } = this.props;
            const { currentLocation, targetLocation } = this.state;
            this.unblock();
            // replacing current location and then pushing navigates to the target otherwise not
            // this is needed when the user tries to change the url manually
            history.replace(currentLocation);
            history.push(targetLocation);
            this.setState(initialState);
        };

        onCancel = () => {
            const { currentLocation } = this.state;
            this.setState(initialState);
            // Replacing the current location in case the user tried to change the url manually
            this.unblock();
            this.props.history.replace(currentLocation);
            this.block(this.props);
        };

        render() {
            return (
                <Prompt
                    {...this.props}
                    isOpen={this.state.isOpen}
                    onCancel={this.onCancel}
                    onConfirm={this.onConfirm}
                />
            );
        }
    }

    return withRouter(NavigationPrompt);
};

export { navigationPromptFactory };

Для того, чтобы использовать вышеупомянутое, вы можете просто предоставить свой пользовательский режим подсказки, например

      const NavigationPrompt = navigationPromptFactory({
           Prompt: AlertDialog
      });
      const whiteListedPathnames = [`${match.url}/abc`, match.url];

       <NavigationPrompt
                when={isEditingPlan}
                cancelLabel={'Stay'}
                confirmLabel={'Leave'}
                whiteListedPathnames={whiteListedPathnames}
                title={'Leave This Page'}
            >
                <span>
                    Unsaved Changes may not be saved
                </span>
      </NavigationPrompt>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...