You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React函数组件转类组件实现(含useMemo等价转换方案)

React 函数组件转类组件完整方案

转换规则说明

  • 原函数组件中useState管理的状态,统一迁移到类组件的state属性中,状态更新调用this.setState方法
  • 原组件内的事件处理函数改写为类的箭头函数属性,自动绑定组件实例上下文,避免this指向错误
  • 原useMemo逻辑的等价实现:useMemo的核心能力是仅在依赖项引用变化时重新计算目标值,其余场景复用缓存结果减少性能损耗。类组件中通过实例属性缓存上一次的依赖值和计算结果,render阶段对比当前依赖和缓存的依赖是否为同一引用,一致则直接返回缓存值,不一致则重新计算并更新缓存,和Hook的行为完全对齐。本场景中分数score仅依赖questions状态,该缓存逻辑可以完全复现原useMemo的效果。

完整转换后代码

import React from "react";
import "./styles.css";

const initialQuestions = [
  {
    id: 1,
    questionText: "What is the capital of France or Ireland?",
    questionType: "checkbox",
    answerOptions: [
      { answerText: "New York", isCorrect: false, checked: false },
      { answerText: "London", isCorrect: false, checked: false },
      { answerText: "Paris", isCorrect: true, checked: false },
      { answerText: "Dublin", isCorrect: true, checked: false }
    ]
  },
  {
    id: 2,
    questionText: "Who is CEO of Tesla or Amazon?",
    questionType: "select",
    answerOptions: [
      { answerText: "Jeff Bezos", isCorrect: true, checked: false },
      { answerText: "Elon Musk", isCorrect: true, checked: false },
      { answerText: "Bill Gates", isCorrect: false, checked: false },
      { answerText: "Tony Stark", isCorrect: false, checked: false }
    ]
  },
  {
    id: 3,
    questionText: "The iPhone was created by which company?",
    questionType: "select",
    answerOptions: [
      { answerText: "Apple", isCorrect: true, checked: false },
      { answerText: "Intel", isCorrect: false, checked: false },
      { answerText: "Amazon", isCorrect: false, checked: false },
      { answerText: "Microsoft", isCorrect: false, checked: false }
    ]
  }
];

class App extends React.Component {
  // 初始化状态,对应原三个useState
  state = {
    currentQuestion: 0,
    showScore: false,
    questions: initialQuestions
  };

  // 缓存useMemo计算结果和依赖,对应原useMemo逻辑
  _renderCache = {
    lastQuestions: null,
    cachedScore: 0
  };

  // 答案选择处理逻辑
  handleAnswerOptionClick = (e, questionId) => {
    const answerTextValue = e.target.value;
    const updatedQuestions = this.state.questions.map((question) => {
      if (question.id === questionId) {
        const updatedAnswersOptions = question.answerOptions.map((answer) => {
          if (answer.answerText === answerTextValue) {
            return { ...answer, checked: !answer.checked };
          } else {
            return question.questionType === "select"
              ? { ...answer, checked: false }
              : answer;
          }
        });
        return { ...question, answerOptions: updatedAnswersOptions };
      } else {
        return question;
      }
    });
    this.setState({ questions: updatedQuestions });
  };

  // 下一题按钮处理逻辑
  handleNext = () => {
    const nextQuestion = this.state.currentQuestion + 1;
    if (nextQuestion < this.state.questions.length) {
      this.setState({ currentQuestion: nextQuestion });
    } else {
      this.setState({ showScore: true });
    }
  };

  render() {
    const { currentQuestion, showScore, questions } = this.state;
    
    // 等价useMemo计算score:依赖questions,引用不变则复用缓存
    let score;
    if (this._renderCache.lastQuestions === questions) {
      score = this._renderCache.cachedScore;
    } else {
      score = questions.reduce((acc, q) => {
        const correctAnswerSelected = q.answerOptions.reduce((ansAcc, answer) => {
          if (answer.checked && answer.isCorrect) {
            ansAcc = ansAcc + 1;
          }
          return ansAcc;
        }, 0);
        return acc + correctAnswerSelected;
      }, 0);
      this._renderCache.lastQuestions = questions;
      this._renderCache.cachedScore = score;
    }

    return (
      <div className="App">
        {showScore ? (
          <div>
            You scored {score} out of {questions.length}
          </div>
        ) : (
          <main className="question">
            {score}
            <div>
              <div>
                <h2>{questions[currentQuestion].questionText}</h2>
              </div>
            </div>
            <div className="question__options">
              {questions[currentQuestion].questionType === "select" &&
                questions[currentQuestion].answerOptions.map(
                  (answerOption, i) => (
                    <React.Fragment key={answerOption.answerText}>
                      <input
                        type="radio"
                        name="radio-group"
                        value={answerOption.answerText}
                        checked={answerOption.checked}
                        onChange={(e) =>
                          this.handleAnswerOptionClick(
                            e,
                            questions[currentQuestion].id
                          )
                        }
                      />
                      <label htmlFor={i}>{answerOption.answerText}</label>
                    </React.Fragment>
                  )
                )}
              {questions[currentQuestion].questionType === "checkbox" &&
                questions[currentQuestion].answerOptions.map(
                  (answerOption, i) => (
                    <div key={answerOption.answerText}>
                      <input
                        className="option"
                        type="checkbox"
                        id={i}
                        value={answerOption.answerText}
                        onClick={(e) =>
                          this.handleAnswerOptionClick(
                            e,
                            questions[currentQuestion].id
                          )
                        }
                      />
                      <label htmlFor={i}>{answerOption.answerText}</label>
                    </div>
                  )
                )}

              <div className="question__submit">
                <button onClick={this.handleNext}>Next</button>
              </div>
            </div>
          </main>
        )}
      </div>
    );
  }
}

export default App;

逻辑一致性说明

转换后的代码和原函数组件运行效果完全对齐:

  • 单选题互斥选择、多选题多选逻辑和原实现一致
  • 分数计算规则完全相同,且保留了原useMemo的缓存能力,不会在每次渲染时重复遍历题目计算分数
  • 题目切换、最终得分页展示逻辑和原实现无差异

内容的提问来源于stack exchange,提问作者Andikatama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 19:06:40