React Hooks useRef初始化问题,useRef仅适用于后续调用

时间:2020-09-07 21:02:53

标签: reactjs react-hooks

我正在将useRef实现到我的项目中。我有一个包含可点击部分的表单。单击后打开表格。我正在使用Reactstrap Collapse来显示/隐藏表单。我需要能够打开表单并显示需要填写的部分,但是,一旦单击该部分,scrollIntoView将无法工作,直到再次打开并关闭表单。我很沮丧在console.log(formRef)中,引用按预期返回了我希望在后续调用中滚动到视口顶部的组件。我的猜测是,formRef首先被初始化为null,因此对ref的初始调用不起作用。但是,一旦知道了ref,后续的调用就会起作用。我不确定该怎么做。

如果我需要提供一个示例,请告诉我。我希望这只是一个初始化问题。

表格

import React, { useRef, useContext, useEffect } from "react";
import {
  FormQuestionsContext,
  FormAnswersContext,
  ExpandedSectionContext,
} from "../../Store";
import SectionHeader from "../SectionHeader";
import ImageUploader from "../CommentsSection";
import Ratings from "../Ratings";
import { Collapse, Button, CardBody, Card } from "reactstrap";
import FontAwesome from "react-fontawesome";
import styles from "./bedthreeform.module.css";

function BedThreeForm({ Name }) {
  const formRef = useRef(null); //useRef Initialization
  const [expandedSection, setExpandedSection] = useContext(
    ExpandedSectionContext
  );
  const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
  const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
  const array = formQuestions.bedthree;
  const onChange = (e, name) => {
    const { value } = e.target;
    setFormAnswers((state) => ({
      ...state,
      [Name]: { ...state[Name], [name]: value },
    }));
  };

  //! The function I use when I want to tell useRef to scrollIntoView
  const handleOpen = () => {
    expandedSection === Name
      ? setExpandedSection("")
      : setExpandedSection(Name);
    formRef.current.scrollIntoView();
  };

  const answeredQuestions = formAnswers.bedthree
    ? Object.keys(formAnswers.bedthree)
    : null;
  console.log(formRef);
  return (
    <div>
      <Button
        className={styles["CollapseBtn"]}
        onClick={handleOpen} //Calling the function here
        style={
          answeredQuestions &&
          answeredQuestions.length === formQuestions.bedthree.length
            ? {
                color: "white",
                ":focus": {
                  backgroundColor: "#02BD43",
                },
                backgroundColor: "#02BD43",
                marginBottom: "1rem",
                width: "100%",
              }
            : answeredQuestions &&
              answeredQuestions.length !== formQuestions.bedthree.length
            ? {
                color: "white",
                ":focus": {
                  backgroundColor: "#bd0202",
                },
                backgroundColor: "#bd0202",
                marginBottom: "1rem",
                width: "100%",
              }
            : {
                ":focus": {
                  backgroundColor: "#fafafa",
                },
                marginBottom: "1rem",
                width: "100%",
              }
        }
      >
        <p>BEDROOM #3 INSPECTION</p>
        <FontAwesome
          className="super-crazy-colors"
          name="angle-up"
          rotate={expandedSection === Name ? null : 180}
          size="lg"
          style={{
            marginTop: "5px",
            textShadow: "0 1px 0 rgba(0, 0, 0, 0.1)",
          }}
        />
      </Button>
      <Collapse
        className={styles["Collapse"]}
        isOpen={expandedSection === Name}
      >
        <Card>
          <CardBody>
            {array ? (
              <div>
                <SectionHeader title="Bedroom #3 Inspection" name={Name} />
                <div
                  ref={formRef}
                  className={styles["BedroomThreeFormWrapper"]}
                  id="bedroom-three-form"
                >
                  {array.map((question, index) => {
                    const selected =
                      formAnswers[Name] && formAnswers[Name][question]
                        ? formAnswers[Name][question]
                        : "";
                    return (
                      <div className={styles["CheckboxWrapper"]} key={index}>
                        <h5>{question}</h5>
                        <Ratings
                          section={Name}
                          question={question}
                          onChange={onChange}
                          selected={selected}
                        />
                      </div>
                    );
                  })}
                </div>
                {!answeredQuestions ? (
                  ""
                ) : (
                  <Button
                    onClick={(e) => e.preventDefault()}
                    style={
                      !answeredQuestions ||
                      (answeredQuestions &&
                        answeredQuestions.length !==
                          formQuestions.bedthree.length)
                        ? {
                            backgroundColor: "#bd0202",
                            color: "white",
                            pointerEvents: "none",
                          }
                        : {
                            backgroundColor: "#02BD43",
                            color: "white",
                            pointerEvents: "none",
                          }
                    }
                  >
                    {!answeredQuestions ||
                    (answeredQuestions &&
                      answeredQuestions.length !==
                        formQuestions.bedthree.length)
                      ? "Incomplete"
                      : "Complete"}
                  </Button>
                )}
                <br />
                <ImageUploader name="bedthree" title={"Bedroom #3"} />
              </div>
            ) : (
              <div></div>
            )}
          </CardBody>
        </Card>
      </Collapse>
    </div>
  );
}

export default BedThreeForm;

CodeSandbox Stripped Form不能按预期工作,但这是剥离的代码。

更新,我愿意接受一些绕过此方法或其他替代方法的建议。我不确定为什么只在后续通话中使用它。

2 个答案:

答案 0 :(得分:0)

看看这些行:

         <CardBody>
            {array ? (
                ...
                <div
                  ref={formRef}
                  ...

仅在定义array的情况下,才会评估此(虚拟)域。如果您想让自己的formRef始终指向dom,则必须将其从条件中删除。

答案 1 :(得分:0)

我已经解决了这个问题,问题是在尚未加载折叠中的内容时调用它,Reactstrap具有属性onEntered,该属性基本上在设置后会尽快运行该函数崩溃完全打开了。我发现的示例是here。此外,通过在Reactstrap组件上设置属性innerRef,我可以像使用ref的常规组件一样操作它。