React Route: 使用 Prompt 控制页面是否跳转

例如,用户编辑表单的某个值,在未保存之前,却无意中点击了其他页面链接,前往新的页面后,之前编辑的数据将全部丢失。

为了阻止类似的现象发生,可以使用 react-router-dom 提供的 Prompt 组件。Prompt 会自动监视用户是否离开页面。 如果满足某个条件,它会在允许离开之前显示警告。

Prompt 带有两个属性,when 和 message,

当 when 为true且用户离开当前页面时显示message。

export interface PromptProps {
    message: string | ((location: H.Location, action: H.Action) => string | boolean);
    when?: boolean | undefined;
}

代码举例

useLeavePage(hooks)

在src目录下创建hooks文件夹

hooks/useLeavePage.ts

import {useState} from 'react';
import {useHistory} from 'react-router-dom';
import {Modal} from 'antd';

const useLeavePage = () => {
    const history = useHistory();

    // 是否已经退出
    const [hasQuit, setHasQuit] = useState(false);
    // 值是否改变
    const [valueChange, setValueChange] = useState(false);

    // 退出提示, 用useCallback有问题
    const handleLeavePage = (location, action) => {
        // action 
        if (action === 'REPLACE' || (action === 'PUSH' && !hasQuit)) {
            setHasQuit(true);
            Modal.confirm({
                title: '退出设置提示',
                content: '直接退出将不再对页面修改内容进行保存,请确认操作',
                okText: '退出',
                onOk: () => {
                    history.push(location);
                    setHasQuit(false);
                },
                onCancel: () => {
                    setHasQuit(false);
                },
            });
            return false;
        }
        return valueChange;
    };

    return {
        valueChange,
        setValueChange,
        handleLeavePage,
    };
};

export default useLeavePage;

使用方法

import {FunctionComponent, useCallback, useEffect, useState} from 'react';
import {Prompt} from 'react-router-dom';
import classnames from 'classnames';
import {isEmpty} from 'lodash-es';
import {Form, Input, Radio, Button, Space, toast} from 'antd';

import useLeavePage from '@/hooks/useLeavePage';

import styles from './styles.module.less';

const FormItem = Form.Item;

const DEFAULT_DATA = {
    age: 10
};

const CustomFrom = props => {
    const [form] = Form.useForm();
    const {
        valueChange,
        setValueChange,
        handleLeavePage
    } = useLeavePage();

    // 初始化获取数据
    const initForm = useCallback(
        () => {
            form.setFieldsValue(DEFAULT_DATA);
        },
        [form, getAlarmStorageConfig, type]
    );

    // 提交表单
    const handleFinish = useCallback(
        async () => {
            const {cleanType, perCameraNum} = await form.validateFields();
            const params = {
                cleanType,
                perCameraNum: +perCameraNum,
                type,
            };
            // TODO
        },
        [form, type, updateAlarmStorageConfig]
    );

    // 监听form值变化
    const handleValuesChange = useCallback(
        () => {
            setValueChange(true);
        },
        [setValueChange]
    );

    // 恢复默认设置
    const handleReset = useCallback(
        () => {
            form.setFieldsValue(DEFAULT_DATA);
            toast.success({message: '恢复默认设置成功'});
            setValueChange(true);
        },
        [form]
    );

    useEffect(
        () => {
            initForm();
        },
        [initForm]
    );

    return (
        <div className={classnames(styles['alarm-storage-config-form'])}>
            <h2>个人信息</h2>
            <Form 
                form={form} 
                labelWidth={144}
                labelAlign="left"
                onValuesChange={handleValuesChange}
            >
                <FormItem
                    name="age"
                    label="年龄"
                    rules={[{required: true, message: '年龄不可为空'}]}
                >
                    <Input style={{width: 120}} />
                </FormItem>
            </Form>
            <Space>
                <Button
                    type="primary"
                    htmlType="submit"
                    loading={loading}
                    onClick={handleFinish}
                >
                    保存
                </Button>
                <Button type="default" htmlType="submit" onClick={handleReset}>
                    重置
                </Button>
            </Space>
            <Prompt when={valueChange} message={handleLeavePage} />
        </div>
    );
};

export default CustomFrom;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值