React useEffect在无限循环内

时间:2020-07-27 12:59:20

标签: reactjs

我正在尝试为表单提交创建垂直步进器。 useEffect的setpersState(stepState);内部的Stepper.jsx中存在一个问题。程序连续运行

当我从useEffect中删除依赖项列表时,它会正常运行,但不会传递更新值。

这是codeandbox链接codesanbok

import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import "./Stepper.scss";

const Stepper = ({
  stepColor,
  steps,
  direction,
  currentStep,
  setStepsState
}) => {
  const [stepState, setStepState] = useState([]);

  useEffect(() => {
    let createSteps = steps.map((step, idx) => ({
      description: step.label,
      component: step.component,
      completed: idx < currentStep - 1, // past are completed
      selected: idx <= currentStep - 1, // past & present are colored
      highlighted: idx === currentStep - 1 // only present is highlighted
    }));
    setStepState(createSteps);
  }, [steps, currentStep]);

  useEffect(() => {
    if (stepState) setStepsState(stepState);
  }, [stepState]);

  return (
    <>
      <div className={`stepper-wrapper-${direction}`}>
        {stepState.map(
          (
            { selected, completed, highlighted, description, component },
            idx
          ) => (
            <div className="step-wrapper" key={idx}>
              <div
                className={`step-number step-number-${
                  selected ? "active" : "disabled"
                }`}
                style={{ background: `${selected ? stepColor : "none"}` }}
              >
                {completed ? "✔" : idx + 1}
              </div>
              <div
                className={`step-description ${
                  highlighted ? "step-description-active" : ""
                }`}
              >
                {description}
              </div>

              {idx + 1 !== stepState.length && (
                <div
                  className={`divider-line divider-line-${stepState.length}`}
                />
              )}
            </div>
          )
        )}
      </div>
    </>
  );
};

Stepper.propTypes = {
  direction: PropTypes.string.isRequired,
  steps: PropTypes.array.isRequired
};

export default Stepper;

1 个答案:

答案 0 :(得分:1)

以下内容完全没有意义:

useEffect(() => {
  if (stepState) setStepsState(stepState);
}, [stepState]);

您将setStepsState作为prop传递,并将其定义为本地状态设置器。

在沙箱中,您可以在App和Step中复制逻辑和状态,并使用App或Step来添加逻辑,而不能同时使用逻辑。

以下是在App中维护逻辑和状态的示例:

const { useEffect, useState } = React;
const Stepper = ({ steps }) => {
  return <pre>{JSON.stringify(steps, undefined, 2)}</pre>;
};
const steps = [
  { label: 'step 1', component: 'component 1' },
  { label: 'step 2', component: 'component 2' },
  { label: 'step 3', component: 'component 3' },
];
const createSteps = (currentStep) =>
  steps.map((step, idx) => ({
    description: step.label,
    component: step.component,
    completed: idx < currentStep - 1, // past are completed
    selected: idx <= currentStep - 1, // past & present are colored
    highlighted: idx === currentStep - 1, // only present is highlighted
  }));
const App = () => {
  const [currentStep, setCurrentStep] = React.useState(1);
  const [stepsState, setsStepState] = useState(
    createSteps(currentStep)
  );

  useEffect(() => {
    setsStepState(createSteps(currentStep));
  }, [currentStep]);
  return (
    <div>
      <button
        onClick={() => setCurrentStep(currentStep + 1)}
      >
        next step
      </button>
      <Stepper steps={stepsState} />
    </div>
  );
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>