Реорганизация компонента класса в функциональный компонент с помощью хуков, получение Uncaught TypeError: func.apply не является функцией

Это моя первая попытка рефакторинга кода из компонента класса в функциональный компонент с помощью перехватчиков React. Причина, по которой мы проводим рефакторинг, заключается в том, что компонент в настоящее время использует метод жизненного цикла componentWillReceiveProps, который скоро будет закрыт, и мы не смогли заставить другие методы жизненного цикла работать так, как мы хотим. В качестве фона исходный компонент имел вышеупомянутый метод жизненного цикла cWRP, функцию handleChange, использовал connect и mapStateToProps и связывается с репозиторием информационных панелей tableau через API tableau. Я также разбиваю компонент, у которого было четыре различных функции, на отдельные компоненты. Код, с которым у меня проблемы, таков:

const Parameter = (props) => {
let viz = useSelector(state => state.fetchDashboard);
const parameterSelect = useSelector(state => state.fetchParameter)
const parameterCurrent = useSelector(state => state.currentParameter)
const dispatch = useDispatch();
let parameterSelections = parameterCurrent;

useEffect(() => {
    let keys1 = Object.keys(parameterCurrent);
    if (
        keys1.length > 0 //if parameters are available for a dashboard
    ) {
        return ({
            parameterSelections: parameterCurrent
        });
    }
}, [props.parameterCurrent])

const handleParameterChange = (event, valKey, index, key) => {
    parameterCurrent[key] = event.target.value;
    console.log(parameterCurrent[key]);
    return (
        prevState => ({
            ...prevState,
            parameterSelections: parameterCurrent
        }),
        () => {
            viz
                .getWorkbook()
                .changeParameterValueAsync(key, valKey)
                .then(function () {
                    Swal.fire({
                        position: "center",
                        icon: "success",
                        title:
                            JSON.stringify(key) + " set to " + JSON.stringify(valKey),
                        font: "1em",
                        showConfirmButton: false,
                        timer: 2500,
                        heightAuto: false,
                        height: "20px"
                    });
                })

                .otherwise(function (err) {
                    alert(
                        Swal.fire({
                            position: "top-end",
                            icon: "error",
                            title: err,
                            showConfirmButton: false,
                            timer: 1500,
                            width: "16rem",
                            height: "5rem"
                        })
                    );
                });
        }
    );
};
const classes = useStyles();
return (
    <div>
        {Object.keys(parameterSelect).map((key, index) => {
            return (
                <div>
                    <FormControl component="fieldset">
                        <FormLabel className={classes.label} component="legend">
                            {key}
                        </FormLabel>
                        {parameterSelect[key].map((valKey, valIndex) => {
                            console.log(parameterSelections[key])
                            return (
                                <RadioGroup
                                    aria-label="parameter"
                                    name="parameter"
                                    value={parameterSelections[key]}
                                    onChange={(e) => dispatch(
                                        handleParameterChange(e, valKey, index, key)
                                    )}
                                >
                                    <FormControlLabel
                                        className={classes.formControlparams}
                                        value={valKey}
                                        control={
                                            <Radio
                                                icon={
                                                    <RadioButtonUncheckedIcon fontSize="small" />
                                                }
                                                className={clsx(
                                                    classes.icon,
                                                    classes.checkedIcon
                                                )}
                                            />
                                        }
                                        label={valKey}
                                    />
                                </RadioGroup>
                            );
                        })}
                    </FormControl>
                    <Divider className={classes.divider} />
                </div>
            );
        })

        }
    </div >
)}; 
export default Parameter;

Классы const определены отдельно, и весь импорт редукторов и т. Д. Был завершен. parameterSelect в коде указывает на все доступные параметры, в то время как parameterCurrent указывает на параметры по умолчанию, выбранные на панели управления (то есть то, что изначально загружает визуализацию).

Происходят две вещи: 1. Все загружается нормально при начальной визуализации, и когда я нажимаю переключатель, чтобы изменить параметр, я вижу, что он обновляется на панели инструментов, однако на самом деле он не показывает, что переключатель выбран (он по-прежнему показывает, какой параметр инициализированной визуализации выбран как выбранный). 2. Когда я щелкаю за пределами панели фильтров (куда импортируется этот компонент), я получаю Uncaught TypeError: func.apply не является функцией. Я провел рефакторинг другого компонента, и у меня не было этой проблемы, и я не могу определить, неправильно ли я закодировал в хуке useEffect, функции handleParameterChange или где-то в операторе return. Любая помощь приветствуется этим новичком !!!


person Rachel Stevens    schedule 14.03.2020    source источник


Ответы (1)


Это большой объем кода, который нужно принять, не видя исходного класса и не имея загружаемой изолированной программной среды. Сначала я подумал, что это может быть ваш useEffect

В отредактированном коде вы указываете useEffect запускать его повторно только при изменении props.parameterCurrent. Однако внутри useEffect вы не используете props.parameterCurrent, вместо этого вы используете parameterCurrent из локальной лексической области. Общее практическое правило: любые значения, используемые в вычислениях внутри useEffect, должны быть в списке зависимостей повторного запуска.

useEffect(() => {
    let keys1 = Object.keys(parameterCurrent);
    if (
        keys1.length > 0 //if parameters are available for a dashboard
    ) {
        return ({
            parameterSelections: parameterCurrent
        });
    }
}, [parameterCurrent])

Однако этот useEffect, похоже, ничего не делает, поэтому, хотя его список зависимостей неверен, я не думаю, что он решит проблему, которую вы описываете.

Я бы посмотрел на вашу рассылку и селектор. Дважды проверьте, что хранилище redux обновляется, как ожидалось, и что новое значение передается из обратного вызова изменения в хранилище и обратно без потери из-за неправильного вложения, неправильных имен ключей и т. Д.

Я бы рекомендовал разместить ссылку на CodeSandbox.io или исходный класс для дальнейшей помощи в отладке.

person Spidy    schedule 14.03.2020
comment
Спасибо! Я пробовал код без хука useEffect (я думал, что он мне нужен для замены метода жизненного цикла), но на самом деле ИТ вызвала вторую ошибку, которая определенно была большей из двух. Я бы с удовольствием разместил это и оригинал на CodeSandbox, но панели мониторинга можно просматривать только в нашей VPN, поэтому я не думал, что это действительно поможет. Когда я выберу вариант с переключателем, я обновлю ответ. Еще раз большое спасибо, Спиди! - person Rachel Stevens; 14.03.2020