在自定义挂钩中反应更新状态,但未返回更新值

时间:2020-01-09 11:31:21

标签: reactjs react-hooks

我正在尝试创建一个使用某种类型的步骤栏的组件,并且该步骤栏需要一些数据(例如当前步骤,更改步骤的方法等)

我正在使用所有这些方法创建一个自定义钩子

export const useSteps = () => {
    const history = useHistory();
    const orderId = useSelector(getCheckinOrderId);
    const checkinHasStarted = useSelector(getCheckinHasStarted);
    const hasMeals = useSelector(hasMealServices);
    const hasBaggage = useSelector(hasBaggageServices);
    const { t } = useTranslation('Checkin');
    const steps: Steps = {
        findBooking: {
            label: t('Find booking')
        },
        baggage: {
            isHidden: !hasBaggage,
            label: t('Baggage')
        },
        meal: {
            isHidden: !hasMeals,
            label: t('Meal')
        },
        seats: {
            label: t('Seats')
        },
        payment: {
            label: t('Payment')
        },
        boardingPass: {
            label: t('Boarding pass')
        }
    };

    const [activeStep, setActiveStep] = useState(
        Object.keys(steps).findIndex(stepKey => history.location.pathname.includes(stepKey))
    );

    const updateActiveStep = () => {
        setActiveStep(Object.keys(steps).findIndex(stepKey => history.location.pathname.includes(stepKey)));
    };

    console.log(activeStep); // properly updates when updateActiveStep() called

    return {
        steps,
        activeStep,
        setStep: (step: CheckinStep) => {
            history.push(`/${orderId}/${step}`);
            updateActiveStep();
        },

        nextStep: (currentStep: CheckinStep, replace = false) => {
            // omitted next step logic

            updateActiveStep();
        },
        previousStep: (currentStep: CheckinStep, replace = false) => {
            //omitted prev step logic

            updateActiveStep();
        }
    };
};

但是当我试图在组件内部获取activeStep变量以将其传递给<Stepbar />组件时,我看到activeStep始终等于初始值< / p>

但是在我的自定义挂钩中,activeStep已正确更新

我像这样使用这个钩子:

const Order: React.FC = () => {
    const isCheckinStarted = useSelector(getCheckinHasStarted);
    const isCheckinCompleted = useSelector(getCheckinHasCompleted);
    const hasBaggage = useSelector(hasBaggageServices);
    const hasMeals = useSelector(hasMealServices);

    const { steps, activeStep, nextStep, setStep } = useSteps();
    console.log(activeStep); // didn't udpate, always initial

    return (
        <div>
            <Stepbar variant="blue" steps={steps} />

            <Switch>
                <Route
                    path="/:id(\d+)"
                    exact
                    render={() => {
                        if (isCheckinStarted) {
                            nextStep(CheckinStep.Passengers, true);

                            return null;
                        }

                        return <Passengers />;
                    }}
                />

                <Route
                    path="/:id(\d+)/baggage"
                    render={() => {
                        if (isCheckinCompleted) {
                            nextStep(CheckinStep.Passengers, true);

                            return null;
                        }

                        if (!hasBaggage) {
                            nextStep(CheckinStep.Baggage, true);

                            return null;
                        }

                        return <Baggage />;
                    }}
                />

                <Route
                    path="/:id(\d+)/meal"
                    render={() => {
                        if (isCheckinCompleted) {
                            nextStep(CheckinStep.Passengers, true);

                            return null;
                        }

                        if (!hasMeals) {
                            nextStep(CheckinStep.Meal, true);

                            return null;
                        }

                        return <Meal />;
                    }}
                />

                <Route
                    path="/:id(\d+)/seats"
                    render={() => {
                        if (isCheckinCompleted) {
                            nextStep(CheckinStep.Passengers, true);

                            return null;
                        }

                        return <Seats />;
                    }}
                />

                <Route
                    exact
                    path="/:id(\d+)/payment"
                    render={() => {
                        if (isCheckinCompleted) {
                            nextStep(CheckinStep.Passengers, true);

                            return null;
                        }

                        return <Payment />;
                    }}
                />

                <Route
                    path="/:id(\d+)/payment/successfull"
                    render={() => {
                        if (isCheckinCompleted) {
                            nextStep(CheckinStep.Passengers, true);

                            return null;
                        }

                        return (
                            <PaymentResult
                                result="success"
                                onClick={reload => {
                                    if (reload) {
                                        location.reload();
                                    } else {
                                        setStep(CheckinStep.Passengers);
                                    }
                                }}
                            />
                        );
                    }}
                />

                <Route
                    path="/:id(\d+)/payment/failed"
                    render={() => {
                        if (isCheckinCompleted) {
                            nextStep(CheckinStep.Passengers, true);

                            return null;
                        }

                        return <PaymentResult result="fail" onClick={() => setStep(CheckinStep.Payment)} />;
                    }}
                />
            </Switch>
        </div>
    );
};

我不知道为什么。

您可以注意带有注释的行,其他代码效果很好。

1 个答案:

答案 0 :(得分:0)

有些奇怪的事情发生了,我在初始化状态时会打印一些调试信息

const [activeStep, setActiveStep] = useState(() => {
  console.log('init for first time');

  return Object.keys(steps).findIndex(stepKey => 

  history.location.pathname.includes(stepKey));

});

当我从父组件更改活动步骤时,每次都会看到此行(第一次初始化)

const updateActiveStep = useCallback(() => {
    console.log('here');
    const newStep = Math.random();
    console.log('before set new step', newStep); // set random float 
    setActiveStep(newStep);
}, [activeStep]);

useEffect(() => {
    console.log(activeStep, 'active step inside hook'); // always Int
}, [activeStep]);