使用 Reducer Hook 使用倒数计时器时,如何停止每秒渲染所有组件?

IT技术 reactjs
2021-05-19 06:28:12

我正在使用带有倒数计时器的旋转木马滑块(底部的演示链接),

一切都运行良好,唯一的细节是每秒渲染所有组件,

这是一种我可以在场景更新时渲染的方式吗?

索引.js

import React, { useReducer, useEffect } from "react";
import ReactDOM from "react-dom";

import First from "./First.js";
import Second from "./Second.js";
import Third from "./Third.js";

import "./styles.css";

const initialState = {
  scene: 1,
  count: 10
};

function reducer(state, action) {
  switch (action.type) {
    case "prev":
      return { scene: state.scene - 1, count: 10 };
    case "next":
      return { scene: state.scene + 1, count: 10 };
    case "dec":
      return { ...state, count: state.count - 1 };
    default:
      throw new Error();
  }
}

function App() {
  console.log("app");
  const limitSlider = 17;
  const [state, dispatch] = useReducer(reducer, initialState);

  useEffect(() => {
    const timer = () => dispatch({ type: "dec" });

    if (state.count <= 0) {
      //stop countdown
      if (state.scene === limitSlider) return;

      //change to the next scene
      dispatch({ type: state.scene + 1 });

      return;
    }

    //reset interval
    const id = setInterval(timer, 1000);
    return () => clearInterval(id);
  }, [state.count, state.scene]);

  return (
    <>
      <First state={state} />
      <Second state={state} />
      <Third state={state} />
      scene: {state.scene} time: {state.count}
      <button
        disabled={state.scene === 1}
        onClick={() => dispatch({ type: "prev" })}
      >
        -
      </button>
      <progress max="" value={`${state.count}%`}>
        {" "}
      </progress>{" "}
      <button
        onClick={() => dispatch({ type: "next" })}
        disabled={state.scene === limitSlider}
      >
        +
      </button>
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

首先.js

import React from "react";

function First(props) {
  console.log("First");

  return (
    <>
      {
        <p style={{ display: props.state.scene === 0 ? "block" : "none" }}>
          First
        </p>
      }
    </>
  );
}

export default First;

第二个.js

import React from "react";

function Second(props) {
  console.log("Second");

  return (
    <>
      {
        <p style={{ display: props.state.scene === 2 ? "block" : "none" }}>
          Second
        </p>
      }
    </>
  );
}

export default Second;

第三个.js

import React from "react";

function Third(props) {
  console.log("Third");

  return (
    <>
      {
        <p style={{ display: props.state.scene === 3 ? "block" : "none" }}>
          Third
        </p>
      }
    </>
  );
}

export default Third;

演示(打开控制台日志)--- https://1i7un.csb.app/

源码----- https://codesandbox.io/s/beautiful-keller-1i7un

1个回答

您可以通过以下方式解决问题:

1.不要将计数器状态传递给子组件,只是场景状态

<First scene={state.scene} />

2.React.memo用于儿童避免重新渲染

export default React.memo(First);

https://codesandbox.io/s/sparkling-monad-st3th