April28项目总结


April 28 项目总结

结论: 

   可以为 modal 传入一个 reactNode (组件),展示这个组件的值(值是时实变化的),

   这个 modal 调用上级组件的方法作为自己的 onOk 和 onCancel ,
     
   在上级组件传入的函数里 执行一些表单操作,
   
   自己 只是做了一个展示作用!
   
   作为被传入 modal 组件的 reactNode ,使用 forwardRef 和 useImperativeHandle 暴露自己的方法和

   值,让得 modal 的 上级组件、(也是自己的上级组件)调用这些方法。

   从而完成表单操作,或者是将这些暴露出来的表单值,
   
   用 useState 或 useRef 将值保存再传给其他需要展示这些数据的组件。
   
   如此,完成了一次比较离奇、奇葩的组件展示、组件值的传递使用。
// SwitchInp

export interface SwitchInpType {
    TITLE_LIST: Array<{
        text: string;
        key: string;
    }>;
    NUMS: string;
}

const SwitchInp: React.FC<SwitchInpType> = props => {
  
    const submitForm = () => {
        hotRef.current.getFormValue();
    };
  
    const handleCancel = () => {
        setVisit(false);
    };
  
      const handleOk = () => {
          const {list, num} = switchRef.current?.getParams();
            query.current = { // 将 switch 组件暴露的实时的值保存其他传给其他组件
                list,
                num,
            };
            // 同步后端接口 , 数量 以及 query 标题
          const hotSearchConfigParams = list.map((item: any) => ({
                appName: item.label,
                name: item.inpVal,
                enable: item.swiVal,
                hotSearchConfigId: item.hotSearchConfigId,
                queryCount: num,
            }));
            const queryCount = num;
            const params = {
                hotSearchConfigParams,
                queryCount,
            };
            (async () => {
                const res = await editHot(params);
                if (res === ZERO) {
                    message.success('变更成功', 1);
                    return;
                }
                message.error('变更失败', 1);
            })();
            setVisit(false);
    };
  
    const modalConfig = () => {
        if (modalType === CREATE || modalType === EDIT) {
            return {
                visit,
                handleOk: submitForm,
                handleCancel,
                reactNode: <CreateHot {...createHotConfig} />,
                NUMS,
                title: TITLE_TWO,
            };
        } else {
            return {
                visit,
                handleOk,
                handleCancel,
                reactNode: (
                    <div style={{textAlign: 'center'}}>
                        <div style={{display: 'inline-block', marginRight: '30px'}}>
                            <SwitchList {...props} ref={switchRef} />
                        </div>
                    </div>
                ),
                NUMS,
                title: TITLE_ONE,
            };
        }
    };

    return (
        <>
           ...
            ..
            <ModalView {...modalConfig()} />
        </>
    );
}
// CreateHot

export interface Mutable { // SwitchInp暴露
    getFormValue: () => void;
    resetForm: () => void;
}

const CreateHot = (props: PropsCreateHot, ref: ForwardedRef<Mutable>) => {
  
      const [form] = Form.useForm();
  
      const resetForm = () => {
        form.resetFields();
      };
      
      ...
      ..
      
      const getFormValue = async () => {
        form.validateFields()
            .then(values => {
                if (values) {
                  // 通过表单校验, 就调接口,无论是新建还是修改
                    if (type === EDIT) {
                        sendParams.hotSearchId = copyFields.hotSearchId || '';
                        (async () => {
                            const res = await editHotSearch(sendParams);
                            if (res === ZERO) { // 若 返回码正确
                                resetForm();
                                message.success('更新成功', 1);
                                getSearchList();
                                handleCancel(); // 再调用父组件的关闭modal方法,这里
                            }                   // 能起到一个阻塞作用
                      })();                     // 如果表单校验失败,或者接口调用失败
                    }                           // 不会关闭modal
                }                               // 而直接在 modal 上级组件 调用完 getFormValue 后
            })                                  // 直接关闭modal,
            .catch(errorInfo => {               // 会出现表单校验爆红,但modal关闭的情况!!
                console.error('errorInfo', errorInfo);
            });
      }
      
    useImperativeHandle(ref, () => {
        return {getFormValue, resetForm};
    });
  
  return (
    <Form
       form={form}
      ...
      ..
    >
    ...
    ..
    </Form>
  )
} 

export default forwardRef<Mutable, PropsCreateHot>(CreateHot);
// SwitchList

interface Refs {
    getParams: () => {
        list: any[];
        num: number;
    };
}

const SwitchList = (props: SwitchInpType, ref: ForwardedRef<Refs>) => {
  
      const {num, numberChange, list, listChange} = useHome(NUMS);
  
      const getParams = () => {
        const defaultVal = list.map((item: any) => {
            if (!item.inpVal) {
                item.inpVal = item.label;
                return item;
            }
            return item;
        });
        return {
            list: defaultVal,
            num,
        };
    };

    useImperativeHandle(ref, () => ({
        getParams,
    }));
  
  return (
          <div className={styles.switchList}>
            {list.map((item, index) => {
                const {label, inpVal, swiVal} = item;
                return (
                    <div key={label} className={styles.listItem} style={{...TYPE_ONE}}>
                        <span className={styles.label}>{label}</span>
                        <Input
                            className={styles.inp}
                        value={inpVal}
                        onChange={e => listChange('inpVal', index, e.target.value)}
                        disabled={swiVal && NUMS !== QUERYNUMS}
                    />
                    <Switch
                        // 这里两个组件会冲突 
                                                // 值得注意的是,自定义hook 只是组件逻辑复用, 不是状态复用
                                                // 但这里一个组件的状态到另一个组件里了..
                        checked={swiVal === ZERO}
                        onChange={e => listChange('swiVal', index, e)}
                        size='default'
                        checkedChildren='开'
                        unCheckedChildren='关'
                        defaultChecked
                    />
                </div>
            );
        })}
    </div>
  )
}

export default forwardRef<Refs, SwitchInpType>(SwitchList);
// ModalView
import React, {ReactNode} from 'react';
import {Modal} from 'antd';
import styles from './index.less';

const SEARCH_NUMS = '搜索数量设置:';

interface Type {
    visit: boolean;
    handleOk: () => void;
    handleCancel: () => void;
    reactNode?: ReactNode;
    NUMS: string;
    title: string;
}

export default (props: Type) => {
    const {visit, handleOk, handleCancel, reactNode, NUMS, title} = props;
    return (
        <>
            <Modal
                width={700}
                title={title}
                visible={visit}
                className={styles.modal}
                onOk={() => {
                    handleOk();
                }}
                onCancel={handleCancel}
                centered
                style={{display: NUMS === SEARCH_NUMS ? 'flex' : ''}}
            >
                {reactNode ? reactNode : null}
            </Modal>
        </>
    );
};
// useHome

import {useState, useEffect} from 'react';
import {getHotConfig} from '@/constants/actions';

// interface SwitchList {
//     label: string;
//     inpVal: string;
//     swiVal: number;
//     hotSearchConfigId?: number;
//     queryCount?: number;
// }

export default (NUMS: string) => {
    const [num, setNum] = useState(1);
    const [list, setList] = useState<any[]>([]);
    console.warn('NUMS', NUMS);

    const numberChange = (val: number) => {
        setNum(val);
    };

    useEffect(() => {
        (async () => {
            const result = await getHotConfig();
            setList(
                result.map((item: any) => ({
                    label: item.appName,
                    inpVal: item.name,
                    swiVal: item.enable,
                    hotSearchConfigId: item.hotSearchConfigId,
                    num: item.queryCount,
                }))
            );
            setNum(result[0].queryCount);
        })();
    }, []);

    const listChange = (flag: string, index: number, value: any) => {
        /**
         * this way space address can not change , so
         * use map .
         * const newList = [] as any;
         * newList[index][flag] = value;
         * setList([...list, ...newList]);
         * console.log('index --- value', index, value);
         */
        setList(
            list.map((item, ind) => {
                if (ind === index) {
                    if (flag === 'swiVal') {
                        item[flag] = value ? 0 : 1;
                        return item;
                    }
                    item[flag] = value;
                    return item;
                }
                return item;
            })
        );
    };

    return {
        num,
        numberChange,
        list,
        listChange,
    };
};

文章作者: KarlFranz
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 reprint policy. If reproduced, please indicate source KarlFranz !
评论
  目录