#javascript #reactjs #typescript #react-hooks #react-functional-component
Вопрос:
некоторые проблемы с состоянием в TypeScript реагируют.
Дочерний компонент передает объект » терминал’ Родительскому через переданную функцию с именем returnTerminal()
. Этот терминальный объект затем сохраняется как состояние использования _object
. useEffect()
говорит, что _object
в конечном итоге это не равно нулю, но callback()
постоянно утверждает, что _object
это равно нулю, и я не уверен, почему.
Родительский компонент
const Parent: React.FunctionComponent<ParentProps> = () => {
const [_object, set_object] = useState<Terminal>(null);
const handleGetTerminal = (terminal: Terminal) => {
set_object(terminal);
};
useEffect(() => {
if (_object !== null) {
_object.writeln("_object is not null"); // This prints just fine
}
}, [_object]);
return (
<Child
returnTerminal={(term) => handleGetTerminal(term)}
callback={() => {
console.log(_object === null); // This returns true - the object is null for some reason???
}}
/>
);
};
Дочерний компонент
const Child: React.FunctionComponent<ChildProps> = (props) => {
const { callback, returnTerminal } = props;
// The ref where the terminal will be stored and returned
const ref = useRef<HTMLDivElement>(null);
// The xterm.js terminal object
const terminal = new Terminal();
useLayoutEffect(() => {
// Calls whenever terminal is typed into
if (callback) terminal.onData(callback);
// Mount terminal to the DOM
if (ref.current) terminal.open(ref.current);
// Pass the terminal to the parent object
returnTerminal(terminal);
}, []);
return <div ref={ref}></div>;
};
export default Child;
callback()
Всегда возвращает значение _object
null, независимо от того, как долго я жду.
Комментарии:
1. Комментарий:
console.log(_object === null); // This returns false - the object is null for some reason???
кажется неправильным. Этоfalse
потому, что у него есть значение, оно НЕ равноnull
?2.
useLayoutEffect
обратный вызов крючка выполняется только один раз и закрывается над областьюcallback
иterminal
в области.const terminal = new Terminal();
также создает новый терминал каждый цикл рендеринга, это намеренно?3. Можете ли вы попробовать заменить
_object === null
наtypeof _object === "object" amp;amp; _object !== null"
, потомуnull
что на самом деле считается типомObject
в JS4. Эта закономерность не является распространенной. Странно, что у вас есть родитель, который имеет значение ребенка. Было бы приятнее, если бы родитель держал объект терминала и передавал его ребенку вместо того, чтобы родителю присваивалась переменная от ребенка
5. @Yooooomi это может быть общий родитель для разных компонентов, которые используют это значение, в этом нет ничего странного.
Ответ №1:
Ответом стало использование useImperativeHandle и forwardRef. Вот готовый код.
Родитель
import Child from "./child";
interface ParentProps {
name?: string;
}
const Parent: React.FunctionComponent<ParentProps> = () => {
type ChildHandle = ElementRef<typeof Child>;
const childRef = useRef<Child>(null);
let _object: Terminal; // same Terminal type that Child uses
useEffect(() => {
if (childRef.current) {
_object = childRef.current.get(); // imperitive handle function
_object.writeln(“_object loaded”);
}
}, []);
return (
<Child
ref={childRef}
callback={() => {
terminal.writeln("_object is not null”); // THIS finally works
}}
/>
);
};
Ребенок
interface ChildProps {
callback?(data: string): void;
}
type ChildHandle = {
get: () => Terminal;
};
const Child: ForwardRefRenderFunction<ChildHandle, ChildProps> = (
props,
forRef
) => {
const { callback } = props;
const terminal = new Terminal();
// The ref where the terminal will be stored and returned
const ref = useRef<HTMLDivElement>(null);
useImperativeHandle(forRef, () => ({
get() {
return terminal;
},
}));
useLayoutEffect(() => {
// Calls whenever terminal is typed into
if (callback) terminal.onData(callback);
// Mount terminal to the DOM
if (ref.current) terminal.open(ref.current);
}, []);
return <div ref={ref}></div>;
};
export default forwardRef(Child);