#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} />