【问题标题】:React - How to let this functional component change div styles?React - 如何让这个功能组件改变 div 样式?
【发布时间】:2020-09-23 11:57:28
【问题描述】:

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

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 来跟踪哪个框被勾选之外,我还没有找到一个好的方法来做到这一点。

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

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

【问题讨论】:

    标签: javascript reactjs stateful react-functional-component


    【解决方案1】:

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

     <Component prop={someValue}/>
    

    唯一的区别是您访问它们的方式。

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

    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,你需要像这样描述你的 props 和 state 的结构

    interface iComponentProps { 
        prop: string;
    };
    
    interface iComponentState { ... };
    
    export default class Component extends React.Component<iComponentProps, iComponentState> { 
      ... 
    }
    

    如果您的组件接受了 props 和/或 state,但您不确定它们的结构,请为您不确定的传递 any


    另一方面,如果我正确理解了您的问题,您可以这样做:

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

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

    您还可以查看useState hook 以使您的功能组件有状态。

    App.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;
    

    AnswerBox.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>
        );
      }
    }
    

    【讨论】:

    • 非常感谢您的详细回复。我稍后会试一试。我再次玩弄了我的应用程序,结果发现它非常容易将道具传递到有状态的组件中。我只是没有正确扩展 React.Component(打字稿),所以传递道具失败了。我需要添加这个:扩展 React.Component
    • 嗨@AllenH.,我也更新了我的答案。是的,它遵循React.Component&lt;Props, State&gt; :)
    • 不错的答案!为了清楚起见,一条评论,如果您不需要构造函数,您可以将其省略并仍然访问this.props。但是如果你确实定义了一个构造函数,你必须像你说的那样调用super(props)。这是因为 React.Component 的构造函数将props 分配给this.props。但是如果没有在你的类中定义构造函数,它会自动发生。
    【解决方案2】:

    对于这种类型的交互,您可以使用输入复选框的checked 属性来显示它已被选中。检查状态应该来自您所在州的某个地方。在 onClick 函数中,您可以查看事件的名称和选中状态以更新您的状态。请注意,如果名称对您来说太笼统,您可以添加任何您想要的属性。

    交互可能如下所示:

    https://codesandbox.io/s/optimistic-archimedes-ozr72?file=/src/App.js

    【讨论】:

      猜你喜欢
      • 2020-04-28
      • 2021-04-21
      • 2021-04-13
      • 2021-11-06
      • 2021-02-01
      • 2021-04-06
      • 1970-01-01
      • 2021-03-08
      • 1970-01-01
      相关资源
      最近更新 更多