reactjs 状态更改时的rtk查询触发器

70gysomp  于 2023-10-17  发布在  React
关注(0)|答案(2)|浏览(135)

我有一个问题,我试图解决一段时间:如何触发此获取:const { data: warrantyInfo } = warrantyApi.useGetWarrantyInfoQuery(materials[0].serialNumber);只有当我键入的东西在serialNumber输入使用setTimeout(),1000
当前在页面加载和用户在serialNumber输入中执行的每种类型时触发。
我尝试了一些方法,但不起作用,因为这是一个钩子,我不能将它用于另一个函数或useEffect

import { useState } from 'react';
import { toast } from 'react-toastify';
import { styled } from '@mui/material/styles';
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import IconButton from '@mui/material/IconButton';
import { isBefore, parseISO } from 'date-fns';
import { ArrowLeft, ArrowRight, ArrowRightLong, CheckOutline, Close, Table, Trash, Upload } from 'assets/icons';
import { Checkbox, FormControlLabel, Grid, InputAdornment, MenuItem, Select, TextField } from '@mui/material';

const ModalAddC = (props) => {
    const { open, handleClose } = props;

    const { t } = useTranslation();

    const [failedSteps] = useState<Array<number>>([]);
    const [activeStep, setActiveStep] = useState<number>(0);
    const [fiveYearWarranty, setFiveYearWarranty] = useState<boolean>(false);
    const [detailedInformation, setDetailedInformation] = useState<string>('' as string);
    const [returnReason, setReturnReason] = useState<string>('' as string);
    const [materialInputType, setMaterialInputType] = useState<boolean>(true);
    const [materials, setMaterials] = useState<Array<{ serialNumber: string; quantity: number; materialDesignation: string }>>([
        { serialNumber: '', quantity: 0, materialDesignation: '' },
    ]);
    const [fileIsUploaded, setFileIsUploaded] = useState<boolean>(false);
    const [commissionName, setCommissionName] = useState<string>('' as string);
    const [billNumber, setBillNumber] = useState<string>('' as string);

    const { data: warrantyInfo } = warrantyApi.useGetWarrantyInfoQuery(materials[0].serialNumber);

    const handleNavigation = (step: number) => {
        if (step < activeStep) {
            setActiveStep(step);
        }
    };

    const handleNext = () => {
        let errors = 0;
        if(!commissionName.length){
            errors = displayError(t('Commission name is required.'));
        }
        if(!billNumber.length){
            errors = displayError(t('Bill number is required.'));
        }
        if(!detailedInformation.length){
            errors = displayError(t('Detailed information is required.'));
        }
        if(!returnReason.length){
            errors = displayError(t('Return reason is required.'));
        }
        if(errors){
            return;
        }
        setActiveStep((current) => current + 1);
    };

    const handleSave = () => {
        let errors = 0;
        materials.forEach((material) => {
            if(!material.serialNumber.length){
                errors = displayError(t('Serial Number is required.'));
            }
            if(!material.quantity){
                errors = displayError(t('Quantity is required.'));
            }
            if(!material.materialDesignation.length){
                errors = displayError(t('Material Designation is required.'));
            }
        })
        if(errors){
            return;
        }
        handleClose();
    };

    const handleDecreaseAmount = (index: number) => {
        if (materials[index].quantity > 0) {
            setMaterials((current) => {
                const newMaterials = [...current];
                newMaterials[index].quantity = newMaterials[index].quantity - 1;
                return newMaterials;
            });
        }
    };
    const handleIncreaseAmount = (index: number) => {
        setMaterials((current) => {
            const newMaterials = [...current];
            newMaterials[index].quantity = newMaterials[index].quantity + 1;
            return newMaterials;
        });
    };
    const handleQuantityChange = (index: number, newValue: number) => {
        setMaterials((current) => {
            const newMaterials = [...current];
            newMaterials[index].quantity = newValue;
            return newMaterials;
        });
    };
    const handleSerialNumberChange = (index: number, newValue: string) => {
        setMaterials((current) => {
            const newMaterials = [...current];
            newMaterials[index].serialNumber = newValue;
            return newMaterials;
        });
    };
    const handleMaterialDesignationChange = (index: number, newValue: string) => {
        setMaterials((current) => {
            const newMaterials = [...current];
            newMaterials[index].materialDesignation = newValue;
            return newMaterials;
        });
    };

    const handleCreateNewMaterial = () => {
        setMaterials((current) => [...current, { serialNumber: '', quantity: 0, materialDesignation: '' }]);
    };

    const handleDeleteMaterial = (index: number) => {
        if (materials.length > 1) {
            setMaterials((current) => {
                const newMaterials = [...current];
                newMaterials.splice(index, 1);
                return newMaterials;
            });
        }
    };

    const handleSubmitCommission = () => {
        const isWarrantyInfoInPast = warrantyInfo
        ? isBefore(parseISO(warrantyInfo?.end_date), new Date())
        : false;
        if(isWarrantyInfoInPast) {
            toast.error(t('According to our record, the warranty has expired! Feel free to contact us with any questions!'));
        } 
        handleSave();
    };

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const readUploadFile = (e: any) => {
        e.preventDefault();
        if (e.target.files) {
            const reader = new FileReader();
            reader.onload = (e) => {
                const data = e.target!.result;
                const workbook = xlsx.read(data, { type: 'array' });
                const sheetName = workbook.SheetNames[0];
                const worksheet = workbook.Sheets[sheetName];
                const json = xlsx.utils.sheet_to_json(worksheet);
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                const newArray = json.map((item: any) => ({
                    serialNumber: item['Material Nummer'],
                    quantity: item['Anazhl'],
                    materialDesignation: '',
                }));
                setMaterials(newArray);
                setFileIsUploaded(true);
            };
            reader.readAsArrayBuffer(e.target.files[0]);
        }
    };

    const openFileInput = () => {
        document.getElementById('hiddenFileInput')!.click();
    };

    return (
        <BootstrapDialog onClose={handleClose} aria-labelledby="customized-dialog-title" open={open} className="rp-modal-add-commission">
            <BootstrapDialogTitle id="customized-dialog-title" onClose={handleClose}>
                <ProgressBar
                    steps={[t('Commission'), t('Material')]}
                    failedSteps={failedSteps}
                    activeStep={activeStep}
                    setActiveStep={(step) => handleNavigation(step)}
                />
            </BootstrapDialogTitle>
            <DialogContent dividers>
                <div className="slider" style={{ transform: `translateX(calc(-${activeStep * 80}vw + ${activeStep * 6}px))` }}>
                    <div className="step">
                        <span className="section-title">{t('Add commission')}</span>
                        <Grid container spacing={0}>
                            <Grid item className="custom-grid" xs={6} md={6} lg={6}>
                                <br></br>
                                <span className="input-label">{t('Commission name').toString() + '*'}</span>
                                <TextField
                                    id="outlined-textfield"
                                    label=""
                                    variant="outlined"
                                    className="custom-text-field"
                                    InputLabelProps={{ shrink: false }}
                                    value={commissionName}
                                    onChange={(e) => setCommissionName(e.target.value)}
                                    error={!commissionName.length}
                                    helperText={!commissionName.length && t('Commission name is required.').toString()}
                                />
                                <FormControlLabel
                                    control={
                                        <Checkbox
                                            color="secondary"
                                            checked={fiveYearWarranty}
                                            onChange={() => setFiveYearWarranty(!fiveYearWarranty)}
                                        />
                                    }
                                    label={`${t('The product has an extended warranty')}(${t('5-years warranty')})`}
                                />
                                <Grid container spacing={0}>
                                    <Grid item className="custom-inside-grid" xs={6} md={6} lg={6}>
                                        <span className="input-label">{t('Serial Number').toString() + (fiveYearWarranty ? '*' : '')}</span>
                                        <TextField
                                            id="outlined-textfield"
                                            label=""
                                            variant="outlined"
                                            className="custom-text-field"
                                            InputLabelProps={{ shrink: false }}
                                        />
                                    </Grid>
                                    <Grid item className="custom-inside-grid" xs={6} md={6} lg={6}>
                                        <span className="input-label">{t('Bill Number').toString() + '*'}</span>
                                        <TextField
                                            id="outlined-textfield"
                                            label=""
                                            variant="outlined"
                                            className="custom-text-field"
                                            InputLabelProps={{ shrink: false }}
                                            value={billNumber}
                                            onChange={(e) => setBillNumber(e.target.value)}
                                            error={!billNumber.length}
                                            helperText={!billNumber.length && t('Bill number is required.').toString()}
                                        />
                                    </Grid>
                                </Grid>
                                <FormControlLabel control={<Checkbox color="secondary" />} label={t('Replacement of this position is desired')} />
                                <span className="input-label">{t('Comment').toString()}</span>
                                <TextField
                                    id="outlined-textfield"
                                    label=""
                                    variant="outlined"
                                    className="custom-text-field"
                                    InputLabelProps={{ shrink: false }}
                                    multiline
                                    rows={2}
                                />
                            </Grid>
                            <Grid item className="custom-grid" xs={6} md={6} lg={6}>
                                <br></br>
                                <span className="input-label">{t('Detailed information').toString() + '*'}</span>
                                <Select
                                    value={detailedInformation}
                                    label=""
                                    onChange={(e) => setDetailedInformation(e.target.value as string)}
                                    color="secondary"
                                    error={!detailedInformation.length}
                                    displayEmpty>
                                    <MenuItem value="" disabled>
                                        <span className="placeholder">{t('Please select').toString()}</span>
                                    </MenuItem>
                                    <MenuItem value={'1'}>
                                        <span className="menu-option">{t('Too many products')}</span>
                                    </MenuItem>
                                    <MenuItem value={'2'}>
                                        <span className="menu-option">{t('Incorrect order')}</span>
                                    </MenuItem>
                                    <MenuItem value={'3'}>
                                        <span className="menu-option">{t('Customer cancelled order')}</span>
                                    </MenuItem>
                                    <MenuItem value={'4'}>
                                        <span className="menu-option">{t('Inventory cleanup')}</span>
                                    </MenuItem>
                                    <MenuItem value={'5'}>
                                        <span className="menu-option">{t('Delivery time')}</span>
                                    </MenuItem>
                                    <MenuItem value={'6'}>
                                        <span className="menu-option">{t('Delivery time too long')}</span>
                                    </MenuItem>
                                    <MenuItem value={'7'}>
                                        <span className="menu-option">{t('Products too expensive / incorrect price')}</span>
                                    </MenuItem>
                                </Select>
                                {!detailedInformation.length && <span className='detailed-information-err-text'>{t('Detailed information is required.')}</span>}
                                <br></br>
                                <span className="input-label">{t('Reason of return').toString() + '*'}</span>
                                <Select
                                    value={returnReason}
                                    label=""
                                    onChange={(e) => setReturnReason(e.target.value as string)}
                                    color="secondary"
                                    error={!returnReason.length}
                                    displayEmpty>
                                    <MenuItem value="" disabled>
                                        <span className="placeholder">{t('Please select').toString()}</span>
                                    </MenuItem>
                                    <MenuItem value={'1'}>
                                        <span className="menu-option">{t('Like new, not needed by customer')}</span>
                                    </MenuItem>
                                    <MenuItem value={'2'}>
                                        <span className="menu-option">{t('Defective')}</span>
                                    </MenuItem>
                                    <MenuItem value={'3'}>
                                        <span className="menu-option">{t('Transport damage')}</span>
                                    </MenuItem>
                                    <MenuItem value={'4'}>
                                        <span className="menu-option">{t('Wrong delivery')}</span>
                                    </MenuItem>
                                    <MenuItem value={'5'}>
                                        <span className="menu-option">{t('Spare parts inventory reconciliation upon consultation')}</span>
                                    </MenuItem>
                                </Select>
                                {!returnReason.length && <span className='return-reason-err-text'>{t('Return reason is required.')}</span>}
                                <br></br>
                                <span className="input-label">{t('Pictures/files for return').toString()}</span>
                                <div className="upload-container">
                                    <Upload className="upload-icon" />
                                    <span className="upload-main-text">{t('Drag or select files here')}</span>
                                    <span className="upload-secondary-text">{t('max. 10MB in  PDF, JPG, PNG format')}</span>
                                </div>
                            </Grid>
                        </Grid>
                    </div>
                    <div className="step">
                        <span className="section-title">{t('Add Material')}</span>
                        <Grid container spacing={0}>
                            <Grid item className="custom-grid" xs={12} md={12} lg={12}>
                                <Toggle
                                    items={[<>{t('Manual input')}</>, <>{t('Excel upload')}</>]}
                                    setToggle={(e) => {
                                        setMaterialInputType(e);
                                        setMaterials([{ serialNumber: '', quantity: 0, materialDesignation: '' }]);
                                        setFileIsUploaded(false);
                                    }}
                                    value={materialInputType}
                                />
                            </Grid>
                        </Grid>
                        {materialInputType ? (
                            <>
                                {materials.map((material, index) => (
                                    <Grid key={'materrial-' + index} container spacing={0}>
                                        <Grid item className="custom-grid" xs={4} md={4} lg={4}>
                                            <span className="input-label">{t('Serial Number').toString()}*</span>
                                            <TextField
                                                id="outlined-textfield"
                                                label=""
                                                variant="outlined"
                                                className="custom-text-field"
                                                InputLabelProps={{ shrink: false }}
                                                value={material.serialNumber}
                                                onChange={(e) => handleSerialNumberChange(index, e.target.value)}
                                                error={!material.serialNumber.length}
                                                helperText={!material.serialNumber.length && t('Serial Number is required.').toString()}
                                            />
                                        </Grid>
                                        <Grid item className="custom-grid" xs={3} md={3} lg={3}>
                                            <span className="input-label">{t('Quantity').toString() + '*'}</span>
                                            <TextField
                                                type="number"
                                                value={material.quantity}
                                                error={!material.quantity}
                                                // onChange={(e) => setPackagestValue(parseInt(e.target.value))}
                                                onChange={(e) => handleQuantityChange(index, parseInt(e.target.value))}
                                                InputProps={{
                                                    startAdornment: (
                                                        <InputAdornment position="start">
                                                            <IconButton onClick={() => handleDecreaseAmount(index)}>
                                                                <ArrowLeft />
                                                            </IconButton>
                                                        </InputAdornment>
                                                    ),
                                                    endAdornment: (
                                                        <InputAdornment position="end">
                                                            <IconButton onClick={() => handleIncreaseAmount(index)}>
                                                                <ArrowRight />
                                                            </IconButton>
                                                        </InputAdornment>
                                                    ),
                                                }}
                                            />
                                            {!material.quantity && <span className='material-qty-err-text'>{t('Quantity is required.')}</span>}
                                        </Grid>
                                        <Grid item className="custom-grid" xs={4} md={4} lg={4}>
                                            <span className="input-label">{t('Material designation').toString()}*</span>
                                            <TextField
                                                id="outlined-textfield"
                                                label=""
                                                variant="outlined"
                                                className="custom-text-field"
                                                InputLabelProps={{ shrink: false }}
                                                value={material.materialDesignation}
                                                onChange={(e) => handleMaterialDesignationChange(index, e.target.value)}
                                                error={!material.materialDesignation.length}
                                                helperText={!material.materialDesignation.length && t('Material Designation is required.').toString()}
                                            />
                                        </Grid>
                                        <Grid item className="custom-grid justify-center" xs={1} md={1} lg={1}>
                                            <Trash className="cursor-pointer" onClick={() => handleDeleteMaterial(index)} />
                                        </Grid>
                                    </Grid>
                                ))}
                                <Grid container>
                                    <Grid item xs={12} md={12} lg={12}>
                                        <button className="add-material-button" onClick={() => handleCreateNewMaterial()}>
                                            {t('Add more materials')}
                                        </button>
                                    </Grid>
                                </Grid>
                            </>
                        ) : (
                            <>
                                {!fileIsUploaded ? (
                                    <>
                                        {materials.map((material, index) => (
                                            <Grid key={'materrial-' + index} container spacing={0}>
                                                <Grid item className="custom-grid" xs={4} md={4} lg={4}>
                                                    <span className="input-label">{t('Serial Number').toString()}*</span>
                                                    <TextField
                                                        id="outlined-textfield"
                                                        label=""
                                                        variant="outlined"
                                                        className="custom-text-field"
                                                        InputLabelProps={{ shrink: false }}
                                                        value={material.serialNumber}
                                                        onChange={(e) => handleSerialNumberChange(index, e.target.value)}
                                                    />
                                                </Grid>
                                                <Grid item className="custom-grid" xs={3} md={3} lg={3}>
                                                    <span className="input-label">{t('Quantity').toString() + '*'}</span>
                                                    <TextField
                                                        type="number"
                                                        value={material.quantity}
                                                        // onChange={(e) => setPackagestValue(parseInt(e.target.value))}
                                                        onChange={(e) => handleQuantityChange(index, parseInt(e.target.value))}
                                                        InputProps={{
                                                            startAdornment: (
                                                                <InputAdornment position="start">
                                                                    <IconButton onClick={() => handleDecreaseAmount(index)}>
                                                                        <ArrowLeft />
                                                                    </IconButton>
                                                                </InputAdornment>
                                                            ),
                                                            endAdornment: (
                                                                <InputAdornment position="end">
                                                                    <IconButton onClick={() => handleIncreaseAmount(index)}>
                                                                        <ArrowRight />
                                                                    </IconButton>
                                                                </InputAdornment>
                                                            ),
                                                        }}
                                                    />
                                                </Grid>
                                                <Grid item className="custom-grid" xs={4} md={4} lg={4}>
                                                    <span className="input-label">{t('Material designation').toString()}*</span>
                                                    <TextField
                                                        id="outlined-textfield"
                                                        label=""
                                                        variant="outlined"
                                                        className="custom-text-field"
                                                        InputLabelProps={{ shrink: false }}
                                                        value={material.materialDesignation}
                                                        onChange={(e) => handleMaterialDesignationChange(index, e.target.value)}
                                                    />
                                                </Grid>
                                                <Grid item className="custom-grid justify-center" xs={1} md={1} lg={1}>
                                                    <Trash className="cursor-pointer" onClick={() => handleDeleteMaterial(index)} />
                                                </Grid>
                                            </Grid>
                                        ))}
                                        <Grid container>
                                            <Grid item xs={12} md={12} lg={12}>
                                                <button className="add-material-button" onClick={() => handleCreateNewMaterial()}>
                                                    {t('Add more materials')}
                                                </button>
                                                <button
                                                    className="add-material-button"
                                                    onClick={() => {
                                                        setFileIsUploaded(false);
                                                        setMaterials([{ serialNumber: '', quantity: 0, materialDesignation: '' }]);
                                                    }}>
                                                    {t('Replace excel file')}
                                                </button>
                                            </Grid>
                                        </Grid>
                                    </>
                                ) : (
                                    <>
                                        <Grid container spacing={0}>
                                            <Grid item className="custom-grid" xs={4} md={4} lg={4}>
                                                <Table />
                                                <br></br>
                                                <span className="excel-upload-description">
                                                    {t('Create your Excel table in the form shown here, or simply use our Excel template.')}
                                                </span>
                                                <br></br>
                                                <button className="add-material-button download-excel-template-button">
                                                    {t('Download Excel template')}
                                                </button>
                                            </Grid>
                                            <Grid item xs={8} md={8} lg={8}>
                                                <div className="upload-container">
                                                    <Upload className="upload-icon" onClick={openFileInput} />
                                                    <span className="upload-main-text">{t('Drag or select files here')}</span>
                                                    <span className="upload-secondary-text">{t('max. 10MB in  xls, csv format')}</span>
                                                </div>
                                                <input
                                                    type="file"
                                                    id="hiddenFileInput"
                                                    style={{ display: 'none' }}
                                                    onChange={readUploadFile}
                                                    accept=".xls, .csv, .xlsx"
                                                />
                                            </Grid>
                                        </Grid>
                                    </>
                                )}
                            </>
                        )}
                        <Grid container spacing={0}>
                            <Grid item className="custom-grid" xs={12} md={12} lg={12}></Grid>
                        </Grid>
                    </div>
                </div>
            </DialogContent>
            <DialogActions>
                {activeStep === 0 && (
                    <>
                        <button className="next-step-btn-negative" onClick={() => handleNext()}>
                            {t('Create and add material later')}
                        </button>
                        <button className="next-step-btn" onClick={() => handleNext()}>
                            {t('Next step')}
                            <ArrowRightLong className="icon" />
                        </button>
                    </>
                )}
                {activeStep === 1 && (
                    <button className="next-step-btn" onClick={() => handleSubmitCommission()}>
                        <CheckOutline className="icon-before" />
                        {t('Create commission')}
                    </button>
                )}
            </DialogActions>
        </BootstrapDialog>
    );
};

export default ModalAddC;
rlcwz9us

rlcwz9us1#

试试这个技巧

import { useEffect, useState } from 'react';

function YourComponent() {
  const [serialNumber, setSerialNumber] = useState('');
  const [debouncedSerialNumber, setDebouncedSerialNumber] = useState('');
  const { data: warrantyInfo } = warrantyApi.useGetWarrantyInfoQuery(debouncedSerialNumber);

  // Update debouncedSerialNumber after a delay
  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setDebouncedSerialNumber(serialNumber);
    }, 1000);

    // Clear the previous timeout when the user types more
    return () => {
      clearTimeout(timeoutId);
    };
  }, [serialNumber]);

  // Handle input change
  const handleInputChange = (e) => {
    setSerialNumber(e.target.value);
  };

  return (
    <div>
      <input
        type="text"
        value={serialNumber}
        onChange={handleInputChange}
        placeholder="Serial Number"
      />
      {/* Render your warrantyInfo data here */}
    </div>
  );
}
b4lqfgs4

b4lqfgs42#

常规的查询钩子旨在每次组件呈现时调用,例如。从状态更新,并将参数传递到底层查询端点。如果你想对查询的触发时间有更多的控制,那么我建议使用惰性查询钩子,并对返回的触发器函数进行反跳。
使用LazyQuery
示例实施方式:

interface Material {
  serialNumber: string;
  quantity: number;
  materialDesignation: string
}
const [materials, setMaterials] = useState<Array<Material>>(
  [{ serialNumber: '', quantity: 0, materialDesignation: '' }]
);

const [
  trigger,
  { data: warrantyInfo }
] = warrantyApi.useLazyGetWarrantyInfoQuery();

...

使用useEffect钩子调用去抖动的trigger函数。

  • 您可以从像lodash这样的库中导入去抖动高阶函数
import { debounce } from 'lodash';
  • 您可以实现自己的简单debounce函数
const debounce = (fn, delay) => {
  let timerId;
  return (...args) => {
    clearTimeout(timerId);
    timerId = setTimeout(() => fn(...args), delay);
  }
};
const debouncedTrigger = React.useCallback(
  debounce(trigger, 1000),
  [trigger]
);

useEffect(() => {
  if (materials[0].serialNumber) {
    // Only call trigger if serial number is truthy
    debouncedTrigger(materials[0].serialNumber);
  }
}, [debouncedTrigger, materials]);

相关问题