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

#javascript #reactjs #react-hooks #react-state-management

#javascript #reactjs #реагирующие хуки #реагирование-управление состоянием

Вопрос:

Я создал 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 amp;amp; 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 amp;amp;
                    output.score !== undefined amp;amp;
                    output.label !== undefined amp;amp;
                    !loading amp;amp; (
                        <div
                            style={{
                                marginTop: "10px",
                                display: "flex",
                                justifyContent: "center",
                            }}
                        >
                            <FontAwesomeIcon
                                icon={faTag}
                                size={"lg"}
                                color={"#f0edee"}
                                style={{ paddingRight: "5px" }}
                            />
                            <div
                                className={
                                    output amp;amp; 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);
  

Комментарии:

1. Было бы здорово, если бы вы разместили эту песочницу . Или создайте там минимальный poc. Здесь много кода. Песочница была бы лучшим вариантом. Другие могут проверять и играть с ними.

2. <HocComponent props={{ ...props, output, loading }} /> похоже, что ваши реквизиты вложены в реквизит с именем props , т. е. props.props.output etc …

3. @DrewReese хороший улов. Это должно быть написано <HocComponent {...props} output={output} loading={loading} />

Ответ №1:

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

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