【问题标题】:State not changing correctly after receiving props from HOC从 HOC 接收道具后状态未正确更改
【发布时间】:2020-11-04 04:18:53
【问题描述】:

我创建了一个 HOC 来处理套接字设置 + 处理程序所需的所有逻辑,并将我的组件包装到其中同时传递 HOC 的状态。我在包装组件中添加了 useEffect 以在它从 HOC 获取新道具后更改它的状态。问题是,即使它在控制台中正确记录了这些道具,它也会以某种方式被破坏。即使在获取道具后也不会显示输出,并且加载微调器一直在工作,尽管加载状态从一开始就设置为 false。有谁知道这可能是什么原因造成的,我该如何解决?

HOC:

import React, { useState, useEffect, useContext } from "react";
import SocketContext from "../../components/sockets/socketContext";
import axios from "axios";
import { SentimentOutput } from "./../../types/outputTypes";
import { TaskLoading } from "./../../types/loadingTypes";




export default function withSocketActions(HocComponent: any) {
    return (props: any) => {
        const [output, setOutput] = useState({
            score: undefined,
            label: undefined,
        });
        const [loading, setLoading] = useState(false);

        const contextProps = useContext(SocketContext);

        useEffect(() => {
            if (contextProps) {
                const { socket } = contextProps;
                socket.on("status", (data: any) => {
                    if (
                        data.message.status === "processing" ||
                        data.message.status === "pending"
                    ) {
                        setLoading(true);
                        console.log(data);
                    } else if (data.message.status === "finished") {
                        setLoading(false);
                        getOutput(data.message.task_id);
                        console.log(data);
                    }
                });
                return () => {
                    socket.off("");
                };
            }
        }, []);

        const getOutput = async (id: string) => {
            const response = await axios.get(`http://localhost:9876/result/${id}`);
            console.log("Output: ", response.data);
            setOutput(response.data);
        };

        return (
            <>
                <HocComponent props={{ ...props, output, loading }} />
            </>
        );
    };
}

组件:

import React, { useState, FormEvent, useEffect, useContext } from "react";
import axios from "axios";
import PulseLoader from "react-spinners/PulseLoader";
import { faTag, faPoll } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import withSocketActions from "../../components/sockets/withSocketActions";

import "../../styles/containers.scss";
import "../../styles/buttons.scss";
import "../../styles/text.scss";

function SentimentInput(props: any) {
    const [input, setInput] = useState("");
    const [output, setOutput] = useState({
        score: "",
        label: "",
    });
    const [loading, setLoading] = useState(false);

    useEffect(() => {
        setOutput({ score: props.output?.score, label: props.output?.label });
        setLoading(props.loading);
        console.log("OUTPUT: ", props);
    }, [props]);

    const getHighlightColour = (label: string | undefined) => {
        if (label === "POSITIVE") return "#57A773";
        else if (label === "NEGATIVE") return "#F42C04";
        else return "transparent";
    };

    const submitInput = async (input: string) => {
        let formData = new FormData();
        formData.set("text", input);
        if (props.model) formData.set("model", props.model);
        const response = await axios.post(
            `http://localhost:9876/run/sentiment_analysis`,
            formData
        );
        console.log("RESPONSE: ", response.data.id);
    };

    const handleSubmit = async (e: FormEvent<HTMLButtonElement>) => {
        e.preventDefault();
        console.log(input);
        const result = await submitInput(input);
    };

    return (
        <div className="inputContainer">
            <div style={{ width: "100%", height: "100%", justifyContent: "center" }}>
                <textarea
                    value={input}
                    onChange={(e) => setInput(e.target.value)}
                    rows={25}
                    className={"inputArea"}
                    readOnly={loading}
                    style={{
                        boxShadow: `0 0 12px 2px ${getHighlightColour(
                            output && output.label
                        )}`,
                    }}
                    autoFocus
                    placeholder={"Insert text for evaluation"}
                />
                <button
                    className={"submitInputButton"}
                    onClick={(e) => handleSubmit(e)}
                >
                    <div className={"topButtonText"}>Evaluate</div>
                </button>
                <PulseLoader loading={loading} color={"white"} size={6} />

                {output &&
                    output.score !== undefined &&
                    output.label !== undefined &&
                    !loading && (
                        <div
                            style={{
                                marginTop: "10px",
                                display: "flex",
                                justifyContent: "center",
                            }}
                        >
                            <FontAwesomeIcon
                                icon={faTag}
                                size={"lg"}
                                color={"#f0edee"}
                                style={{ paddingRight: "5px" }}
                            />
                            <div
                                className={
                                    output && output.label === "POSITIVE"
                                        ? "outputInfo labelPositive"
                                        : "outputInfo labelNegative"
                                }
                            >
                                {output.label}
                            </div>

                            <FontAwesomeIcon
                                icon={faPoll}
                                size={"lg"}
                                color={"#f0edee"}
                                style={{ paddingRight: "5px" }}
                            />
                            <div className={"outputInfo"}>{output.score}</div>
                        </div>
                    )}
            </div>
        </div>
    );
}

export default withSocketActions(SentimentInput);

【问题讨论】:

  • 如果您发布此sandbox,那就太好了。或者在那里创建最小 poc。这里有很多代码。沙盒会是更好的选择。其他人可以在那里查看和玩。
  • &lt;HocComponent props={{ ...props, output, loading }} /&gt; 似乎将您的道具嵌套在名为props 的道具中,即props.props.output 等...
  • @DrewReese 不错。应该写成&lt;HocComponent {...props} output={output} loading={loading} /&gt;

标签: javascript reactjs react-hooks react-state-management


【解决方案1】:

写@Drew 的评论作为答案

&lt;HocComponent props={{ ...props, output, loading }} /&gt;
看起来将您的道具嵌套在名为 props 的道具中,即 props.props.output
改成-
&lt;HocComponent {...props} output={output} loading={loading} /&gt;

【讨论】:

    猜你喜欢
    • 2020-01-16
    • 2018-09-16
    • 2020-09-22
    • 2017-05-25
    • 2021-12-14
    • 1970-01-01
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多