Reputation: 1
I have read this post [ https://brettdewoody.com/accessing-component-methods-and-state-from-outside-react/ ]
But I don't understand.
that is not working on my source code.
it's my tsx file
declare global {
interface Window {
fn_test(): void;
childComponent: HTMLDivElement; <-- what the... ref type????
}
}
export default function Contact(): React.ReactElement {
....
function file_input_html( i:number ): React.ReactElement {
return (
<form id={`frm_write_file_${i}`} .... </form>
)
}
....
return (
<div ref={(childComponent) => {window.childComponent = childComponent}}>
....
)
it's my external javascript file
function fn_test(){
window.childComponent.file_input_html(3)
var element = document.getElementById("ifrm_write_file");
// element.value = "mystyle";
}
How can i call file_input_html function?
plase help me ...
Upvotes: 0
Views: 208
Reputation: 17
안녕하세요. 자바스크립트로 흐름만 알려드리겠습니다
아래 코드들을 참고해보세요.
iframe간 통신은
window.postMessage
API와
window.addEventListener('message', handler)
메시지 수신 이벤트 리스너 로 구현할 수있습니다. 보안관련해서도 방어로직이 몇줄 필요합니다(origin 체크 등)
in parent
import React from 'react';
export function Parent () {
const childRef = React.useRef(null);
const handleMessage = (ev) => {
// 방어로직들
if (check ev.origin, check ev.source, ....) {
return false;
}
console.log('handleMessage(parent)', ev)
}
React.useEffect(() => {
window.addEventListener('message', handleMessage);
// clean memory
return () => {
window.removeEventListener('message', handleMessage);
}
})
return (
<div>
<iframe ref="childRef" src="child_src" id="iframe"></iframe>
</div>
)
}
in child
import React from 'react';
export function Iframe () {
const handleMessage = (ev) => {
console.log('handleMessage(child)', ev)
}
const messagePush = () => {
window.parent.postMessage({ foo: 'bar' }, 'host:port')
}
React.useEffect(() => {
window.addEventListener('message', handleMessage);
// clean memory
return () => {
window.removeEventListener('message', handleMessage);
}
})
return (
<div>
<button onClick={messagePush}>Push message</button>
</div>
)
}
Upvotes: 0
Reputation: 52475
You have some logic here that doesn't completely make sense.
In your class, you define file_input_html
, which returns a component.
Then, in fn_test
, you call attempt to call that function (which doesn't work -- I'll address that in a minute), but you don't do anything with the output.
The article that you linked to tells you how to get a ref to a component (eg the div
in this case) -- not the actual Contact
, which doesn't have a property named file_input_html
anyway -- that's just a function you declared inside its scope.
What I'm assuming you want to happen (based on the code you shared) is for your external javascript file to be able to tell your component to render a form with a certain ID and then be able to get a reference to it. Here's an example of how to do this (it's a little convoluted, but it's a funny situation):
const { useState } = React
const App = (props) => {
const [formId, setFormId] = useState(2)
useEffect(() => {
window.alterFormId = setFormId
},[])
return (<div id={"form" + formId} ref={(ourComponent) => {window.ourComponent = ourComponent}}>
Text {formId}
</div>);
}
setTimeout(() => {
window.alterFormId(8);
setTimeout(() => {
console.log(window.ourComponent)
window.ourComponent.innerText = "Test"
}, 20)
}, 1000)
ReactDOM.render(<App />,
document.getElementById("root"))
What's happening here:
useEffect
, I set alterFormId
on window
so that it can be used outside of the React filesref
to the div that's created. Note that I'm setting the ID here as well, based on the state of formId
setTimeout
function at the end tests all this:
a) It waits until the first render (the first setTimeout) and then calls alterFormId
b) Then, it waits again (just 20ms) so that the next run loop has happened and the React component has re-rendered, with the new formId and reference
c) From there, it calls a method on the div just to prove that the reference works.I'm not exactly sure of your use case for all this and there are probably easier ways to architect things to avoid these issues, but this should get you started.
Upvotes: 1