首页 > 解决方案 > React - 如何让这个功能组件改变 div 样式?

问题描述

我有点反应新手所以请对我温柔。我正在尝试构建一个教育应用程序,代码是呈现多项选择答案框:

export default function AnswerBox(props: any) {
    return (
        <div className="answer-container">
            <ul>
                {props.answers.map((value: any) => {
                    return (
                    <li className="answer-box" key={value.letter} id={value.letter}>
                        <input className="answer-textbox" type="checkbox" onChange={() => console.log('selected: ', value.letter)}></input>
                        <span className="answer-letter"><b>{value.letter})</b></span>
                        {value.answer}
                    </li>)
                })
                }
            </ul>
        </div>
    )
}

如您所见,该函数采用数组对象并遍历数组以在无序列表中显示问题字母(例如“A”)和问题答案。

所以这一切都很好,但我希望突出显示列表元素或在实际选择时更改答案框 div。除了将组件更改为有状态组件并使用 state var 来跟踪哪个框被勾选之外,我还没有找到一个好的方法来做到这一点。

但是当我昨晚将它更改为有状态组件时,我真的很难传入要渲染的对象列表。

我怎样才能有一个有状态的类,它也像常规功能组件一样接受道具?

标签: javascriptreactjsstatefulreact-functional-component

解决方案


首先,您以类似的方式将 props 传递给所有类型的组件,无论它是否有状态。

 <Component prop={someValue}/>

唯一的区别是您将如何访问它们。

对于基于类的组件,您可以通过propsclass 的属性访问它们this.props。IE

class Component extends React.Component {
  constructor(props) {
     // you need to call super(props) otherwise
     // this.props will be underfined
     super(props);
  }

  ...
  someFunction = (...) => {
     const value = this.props.prop;
  }
}

如果您使用的是 TypeScript,则需要向它描述您的道具的结构和状态,如下所示

interface iComponentProps { 
    prop: string;
};

interface iComponentState { ... };

export default class Component extends React.Component<iComponentProps, iComponentState> { 
  ... 
}

如果您的组件接受道具和/或状态并且您不确定它们的结构,请传递any您不确定的那个。


另一方面,如果我正确理解了您的问题,您可以执行以下操作:

我还演示了我为解决您的其他问题而制作的简单应用程序。

总之,您可以让您的AnswerBox组件维护一个与每个选项相关的索引数组,并在每次选择(或单击)选项时通过使用更新它setState

您还可以检查useState钩子以使您的功能组件有状态。

应用程序.js

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

export default function App() {
  const questionData = [
    {
      question: "Some Question that needs to be answered",
      choices: ["Letter A", "Letter B", "Letter C"]
    },
    {
      question: "Another Question that needs to be answered",
      choices: ["Letter A", "Letter B", "Letter C"]
    }
  ];
  return (
    <div className="App">
      {questionData.map(question => (
        <Question questionText={question.question} choices={question.choices} />
      ))}
    </div>
  );
}

问题.js

import React from "react";
import AnswerBox from "./AnswerBox";

const Question = ({ questionText, choices }) => {
  return (
    <div className={"question-container"}>
      <p className={"question-text"}>{questionText}</p>
      <AnswerBox choices={choices} />
    </div>
  );
};

export default Question;

QuestionChoice.js

import React from "react";
import clsx from "clsx";

const QuestionChoice = ({ letter, content, isSelected, handleClick }) => {
  return (
    <li
      className={clsx("question-choice-container", {
        "selected-choice": isSelected
      })}
    >
      <input type={"checkbox"} value={content} onClick={handleClick} />
      <label for={content} className={"question-choice-label"}>
        <strong>{letter.toUpperCase()}. </strong>
        <span>{content}</span>
      </label>
    </li>
  );
};

export default QuestionChoice;

答案框.js

import React, { PureComponent } from "react";
import QuestionChoice from "./QuestionChoice";

export default class AnswerBox extends PureComponent {
  constructor(props) {
    super(props);
    this.choiceLetters = Array.from("abcdefghijklmnopqrstuvwxyz");
    this.state = { activeChoices: [] };
  }

  _updateActiveChoices = index => {
    let updatedList = [].concat(this.state.activeChoices);
    if (this.state.activeChoices.indexOf(index) !== -1) {
      updatedList.splice(updatedList.indexOf(index), 1);
    } else {
      updatedList.push(index);
    }

    return updatedList;
  };

  _handleChoiceSelect = choiceIndex => () => {
    // an update to your component's state will
    // make it re-run its render method
    this.setState({ activeChoices: this._updateActiveChoices(choiceIndex) });
  };

  render() {
    return (
      <ul class={"answer-box"}>
        {this.props.choices.map((choice, index) => (
          <QuestionChoice
            letter={this.choiceLetters[index]}
            content={choice}
            isSelected={this.state.activeChoices.indexOf(index) != -1}
            handleClick={this._handleChoiceSelect(index)}
          />
        ))}
      </ul>
    );
  }
}

推荐阅读