Refactoring class component to functional component with hooks, getting Uncaught TypeError: func.apply is not a function

夙愿已清 提交于 2021-01-29 20:37:31

问题


This is my first attempt to refactor code from a class component to a functional component using React hooks. The reason we're refactoring is that the component currently uses the soon-to-be-defunct componentWillReceiveProps lifecylcle method, and we haven't been able to make the other lifecycle methods work the way we want. For background, the original component had the aforementioned cWRP lifecycle method, a handleChange function, was using connect and mapStateToProps, and is linking to a repository of tableau dashboards via the tableau API. I am also breaking the component, which had four distinct features, into their own components. The code I'm having issues with is this:

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;

The classes const is defined separately, and all imports of reducers, etc. have been completed. parameterSelect in the code points to all available parameters, while parameterCurrent points to the default parameters chosen in the dashboard (i.e. what the viz initially loads with).

Two things are happening: 1. Everything loads fine on initial vizualization, and when I click on the Radio Button to change the parameter, I can see it update on the dashboard - however, it's not actually showing the radio button as being selected (it still shows whichever parameter the viz initialized with as being selected). 2. When I click outside of the Filterbar (where this component is imported to), I get Uncaught TypeError: func.apply is not a function. I refactored another component and didn't have this issue, and I can't seem to determine if I coded incorrectly in the useEffect hook, the handleParameterChange function, or somewhere in the return statement. Any help is greatly appreciated by this newbie!!!


回答1:


This is a lot of code to take in without seeing the original class or having a code sandbox to load up. My initial thought is it might be your useEffect

In your refactored code, you tell your useEffect to only re-run when the props.parameterCurrent changes. However inside the useEffect you don't make use of props.parameterCurrent, you instead make use of parameterCurrent from the local lexical scope. General rule of thumb, any values used in the calculations inside a useEffect should be in the list of re-run dependencies.

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

However, this useEffect doesn't seem to do anything, so while its dependency list is incorrect, I don't think it'll solve the problem you are describing.

I would look at your dispatch and selector. Double check that the redux store is being updated as expected, and that the new value is making it from the change callback, to the store, and back down without being lost due to improper nesting, bad key names, etc...

I'd recommend posting a CodeSandbox.io link or the original class for further help debugging.



来源:https://stackoverflow.com/questions/60678759/refactoring-class-component-to-functional-component-with-hooks-getting-uncaught

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!