Состояние некорректно меняется после получения реквизита от HOC

Я создал 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);

person user11569827    schedule 04.11.2020    source источник
comment
Было бы здорово, если бы вы разместили эту песочницу. Или создайте там минимум poc. Здесь много кода. Песочница была бы лучшим вариантом. Другие могут там проверить и поиграть.   -  person Shubham Verma    schedule 04.11.2020
comment
<HocComponent props={{ ...props, output, loading }} /> похоже, вкладывает ваши реквизиты в реквизит с именем props, то есть props.props.output и т. Д.   -  person Drew Reese    schedule 04.11.2020
comment
@DrewReese хороший улов. Должно быть написано <HocComponent {...props} output={output} loading={loading} />   -  person Seth Lutske    schedule 04.11.2020


Ответы (1)


Написание комментария @Drew в качестве ответа

<HocComponent props={{ ...props, output, loading }} />
похоже, что ваши реквизиты вкладываются в реквизит с именем props, т.е. props.props.output
измените его на-
<HocComponent {...props} output={output} loading={loading} />

person Vikrant    schedule 04.11.2020