javascript - 如何在 React 中同步组件共享状态钩子(Hook)

标签 javascript reactjs material-ui react-hooks

我正在尝试使用 React hooks 使 2 个组件与其父组件状态同步。 我使用水平垂直步进器作为来自 Material UI的2个独立组件,它们的父类具有步进器的内容以及它们的状态应该分享。 我使用水平垂直步进器的原因是为了使 UI 尽可能响应。

我遇到的问题是,根据我对组件安装生命周期的理解,当 activeStep 由组件之一(即水平步进器)递增时。调用 render 方法,Activestep 递增并反射(reflect)在 dom 中。但它仅反射(reflect)在水平步进器上。该变化仅在水平步进器组件中传播。当导航垂直步进器组件时,它返回最初设置为 0 的钩子(Hook)的初始状态。

我正在尝试使水平垂直步进器stepperContent中的activeStep同步,并且状态的任何变化都应该在两个组件中传播。

我的问题是

如何使它们与 stepperContent 有状态功能组件中的 activeState 同步?

steppertContent.JSX

import { makeStyles } from "@material-ui/core/styles";
import { useState, useEffect } from "react";

export const useVerticalStyles = makeStyles((theme) => ({
  root: {
    width: "100%",
  },
  button: {
    marginTop: theme.spacing(1),
    marginRight: theme.spacing(1),
  },
  actionsContainer: {
    marginBottom: theme.spacing(2),
  },
  resetContainer: {
    padding: theme.spacing(3),
  },
}));

export const useHorizontalStyles = makeStyles((theme) => ({
  root: {
    width: "100%",
  },
  backButton: {
    marginRight: theme.spacing(1),
  },
  instructions: {
    marginTop: theme.spacing(1),
    marginBottom: theme.spacing(1),
  },
}));

export const StepperContent = () => {
  const [activeStep, setActiveStep] = useState(0);

  useEffect(() => {
    console.log(activeStep);
  }, [activeStep]);
  // console.log(activeStep);

  const handleNext = () => {
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
  };

  const handleBack = () => {
    setActiveStep((prevActiveStep) => prevActiveStep - 1);
  };

  const handleReset = () => {
    setActiveStep(0);
  };
  return { activeStep, handleNext, handleBack, handleReset };
};

export const getSteps = () => {
  return [
    "ACCOUNT SETUP",
    "PERSONAL INFORMATION",
    "CONTACT INFORMATION",
    "FAMILY INFORMATION",
    "SCHOOL INFORMATION",
    "ADMISSION INFORMATION",
    "SUBMIT INFORMATION",
  ];
};

export const getStepContent = (stepIndex) => {
  switch (stepIndex) {
    case 0:
      return "CREATE YOUR ACCOUNT";
    case 1:
      return "What is an ad group anyways?";
    case 2:
      return "This is the bit I really care about!";
    default:
      return "Unknown stepIndex";
  }
};

horizo​​ntalFormStepper.JSX

import React from "react";
import {
  Stepper,
  Step,
  StepLabel,
  Button,
  Typography,
} from "@material-ui/core/";
import {
  getStepContent,
  getSteps,
  useHorizontalStyles,
  StepperContent,
} from "./common/stepperContent";

const HorizontalFormStepper = () => {
  const classes = useHorizontalStyles();
  const { activeStep, handleReset, handleBack, handleNext } = StepperContent();
  const steps = getSteps();

  return (
    <div className={classes.root}>
      <Stepper activeStep={activeStep} alternativeLabel>
        {steps.map((label) => (
          <Step key={label}>
            <StepLabel>{label}</StepLabel>
          </Step>
        ))}
      </Stepper>
      <div>
        {activeStep === steps.length ? (
          <div>
            <Typography className={classes.instructions}>
              All steps completed
            </Typography>
            <Button onClick={handleReset}>Reset</Button>
          </div>
        ) : (
          <div>
            <Typography className={classes.instructions}>
              {getStepContent(activeStep)}
            </Typography>
            <div>
              <Button
                disabled={activeStep === 0}
                onClick={handleBack}
                className={classes.backButton}
              >
                Back
              </Button>
              <Button variant="contained" color="primary" onClick={handleNext}>
                {activeStep === steps.length - 1 ? "Finish" : "Next"}
                {/* {console.log(steps.length - 1)} */}
              </Button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};

export default HorizontalFormStepper;

verticalFormStepper.JSX

import React from "react";
import {
  Stepper,
  Step,
  StepLabel,
  StepContent,
  Button,
  Paper,
  Typography,
  Grid,
  Container,
} from "@material-ui/core/";
import {
  getStepContent,
  getSteps,
  useVerticalStyles,
  StepperContent,
} from "./common/stepperContent";

const VerticalFormStepper = () => {
  const classes = useVerticalStyles();
  const steps = getSteps();
  const { activeStep, handleBack, handleNext, handleReset } = StepperContent();
  return (
    <Container fixed maxWidth="sm">
      <Grid>
        <Paper variant="outlined" elevation={2}>
          <div className={classes.root}>
            <Stepper activeStep={activeStep} orientation="vertical">
              {steps.map((label, index) => (
                <Step key={label}>
                  <StepLabel>{label}</StepLabel>
                  <StepContent>
                    <Typography>{getStepContent(index)}</Typography>
                    <div className={classes.actionsContainer}>
                      <div>
                        <Button
                          disabled={activeStep === 0}
                          onClick={handleBack}
                          className={classes.button}
                        >
                          Back
                        </Button>
                        <Button
                          variant="contained"
                          color="primary"
                          onClick={handleNext}
                          className={classes.button}
                        >
                          {activeStep === steps.length - 1 ? "Finish" : "Next"}
                        </Button>
                      </div>
                    </div>
                  </StepContent>
                </Step>
              ))}
            </Stepper>
            {activeStep === steps.length && (
              <Paper square elevation={0} className={classes.resetContainer}>
                <Typography>
                  All steps completed - you&apos;re finished
                </Typography>
                <Button onClick={handleReset} className={classes.button}>
                  Reset
                </Button>
              </Paper>
            )}
          </div>
        </Paper>
      </Grid>
    </Container>
  );
};

export default VerticalFormStepper;

最佳答案

另一种可能的解决方案是使用 Context API。

// StepperContent.jsx
...

export const StepperContentContext = createContext();
export const useStepperContent = () => useContext(StepperContentContext);

export const StepperContentProvider = ({ children }) => {
  ...

  const value = { activeStep, handleNext, handleBack, handleReset };

  return (
    <StepperContentContext.Provider value={value}>
      {children}
    </StepperContentContext.Provider>
  );
};

因此,您现在可以使用 useStepperContent Hook ,而不是使用 StepperContent

// HorizontalFormStepper.jsx
...
import {
  getStepContent,
  getSteps,
  useHorizontalStyles,
  useStepperContent
} from "./common/StepperContent";

const HorizontalFormStepper = () => {
  const classes = useHorizontalStyles();
  const {
    activeStep,
    handleReset,
    handleBack,
    handleNext
  } = useStepperContent();
  ...

Edit sleepy-bell-2pgq2

可能有点矫枉过正,但它就在那里。

关于javascript - 如何在 React 中同步组件共享状态钩子(Hook),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63857578/

相关文章:

javascript - 无法访问数组中的单个对象?

javascript - 带有 React Router 4 实现的 Material UI AppBar 不起作用

javascript - innerHTML 将 CDATA 转换为注释

javascript - 什么是好的 JavaScript 插件颜色选择器?

c# - 调用 javascript 失败,$ 未定义

javascript - 在 React 中切换 View 时保留输入值

javascript - 调度和监听不同组件中的事件 - reactjs

reactjs - 使 Material UI 容器组件具有响应能力

reactjs - React 中表格的 Material-UI 错误

javascript - .each() 将属性添加到从 jquery 到 js 的父级