使用钩子将类组件重构为功能组件,得到Uncaught TypeError:func.apply不是函数

时间:2020-03-14 00:43:00

标签: reactjs react-hooks react-lifecycle

这是我第一次使用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类,并且所有的reducer等的输入都已完成。代码中的parameterSelect指向所有可用参数,而parameterCurrent指向在仪表板中选择的默认参数(即Viz最初加载的内容)。

正在发生两件事:1.初始Vizualization时一切正常,当我单击“单选按钮”更改参数时,我可以在仪表板上看到它的更新-但是,实际上并没有显示单选按钮为已选择(仍显示被初始化的那个参数)。 2.当我在“过滤器栏”(此组件被导入到的地方)之外单击时,出现Uncaught TypeError:func.apply不是一个函数。我重构了另一个组件,但没有出现这个问题,而且似乎无法确定在useEffect挂钩,handleParameterChange函数或return语句中的位置是否编码错误。此新手将不胜感激!

1 个答案:

答案 0 :(得分: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存储是否正在按预期进行更新,并且新值正在从change回调到存储,然后回退,并且不会因嵌套不正确,键名错误等而丢失...

我建议发布CodeSandbox.io链接或原始类,以进行进一步的调试。