Use component function in React loop - reactjs

I heard that () is not good at the rendering performance so it should not be used. However, in this case, it can not get the results when passing the function without ().
You can check the reseult in CodeSendbox: Link
const comp = () => {
return <div>This is Component</div>;
};
const elements = [comp(), comp]; // Please Attention This Line!
const items = [];
for (const [index, value] of elements.entries()) {
items.push(
<div>
{index}: {value} <br />
</div>
);
}
export default function Index() {
return <>{items}</>;
}
Result is:
0:
This is Component
1:
Why only comp() but not comp? What is the best practice in this case?

You can use JSX instead of calling the function:
const comp = () => {
return <div>This is Component</div>;
};
const elements = [comp, comp]; // Remove the function call, save only the reference
const items = [];
// need to use Value with V instead of v for JSX
for (const [index, Value] of elements.entries()) {
items.push(
<div>
{index}: <Value/> <br /> // render as JSX
</div>
);
}
export default function Index() {
return <>{items}</>;
}
Here's a sandbox link showing how it works: https://codesandbox.io/s/cranky-mclean-7ymzr

comp is an arrow function that returns a JSX literal. It's a "function" that is stored in a variable called comp. When called/invoked as comp(), notice the parenthesis, it is executed and the computed return value is returned in the array. When used without the parenthesis, like comp, this is simply the reference to the variable (that can be invoked like a function).
Functions aren't valid react children nor valid JSX.
Introducing JSX
const comp = () => {
return <div>This is Component</div>;
};
const elements = [comp(), comp]; // saves a JSX literal, and a function
const items = [];
for (const [index, value] of elements.entries()) {
items.push(
<div>
{index}: {value} <br /> // trying to render a function here in `value`
</div>
);
}
export default function Index() {
return <>{items}</>;
}
I assume you got the idea () is "not good at rendering performance" from some documentation about in-line anonymous arrow functions and event handlers and mapping an array of data. That is a different issue altogether. I believe your situation is just a misunderstanding about how arrow functions are invoked.

Related

Pass a reference to a DOM element into React

I have a reference to a DOM element (from a 3rd-party library) and need to render it it React. I can think of a couple ways do this, but I'm hoping to find a solution that's more straightforward and doesn't require converting the element to a string first. For example:
const el = document.createElement('div');
el.textContent = 'test';
// This works but requires converting the element to a string first.
const reactEl = (
<div dangerouslySetInnerHTML={{__html: el.innerHTML}} />
);
// Something like this should also work, but it seems overly complicated.
function MyComponent() {
const myRef = useRef();
useEffect(() => {
myRef.current.appendChild(el);
}, []);
return (
<div ref={myRef} />
);
}
Is there another, more straightforward way to insert a DOM element into jsx?
Your second method is the correct way to do it in React. It may seem complicated, but it's not.
function MyComponent() {
const myRef = useRef();
useEffect(() => {
myRef.current.appendChild(el);
}, []);
return (
<div ref={myRef} />
);
}

How to call react function from external JavaScript file

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 ...
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:
In useEffect, I set alterFormId on window so that it can be used outside of the React files
Using the technique you linked to, I get a ref to the div that's created. Note that I'm setting the ID here as well, based on the state of formId
The 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.
안녕하세요. 자바스크립트로 흐름만 알려드리겠습니다
아래 코드들을 참고해보세요.
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>
)
}

Element not being found

I am having an issue where I have an element, but I cannot seem to reference it without getting a null error.
render() {
const getXandY = () => {
const elment = document.getElementById("test");
const xpos = elment.style.left;
const ypos = elment.style.top;
console.log(xpos);
console.log(ypos);
};
return (
getXandY(),
(
<div id="test" className="treeContainer">
{this.state.configs.map((config) => (
<div>
<Configs configName={config.name} configNumber={config.id} />
</div>
))}
</div>
)
);
}
}
any help is appreciated.
I'm not sue you understand React. In render() function try to avoid defining functions, it's a function for just returning the JSX you want to render (you can't return nothing else there). So define your getXandY outside render(). If you really want to invoke it on rendering, simply put the function call inside, that's it. So it would look something like:
const getXandY = ...
render() {
getXandY();
return (
<div ... />
);
{

Issue with returning react component from function

I am trying to return a list of myCustomComponent from a list so they it can be rendered but it throws this error or goes into the infinity loop. The error is as follows:
Expected an assignment or function call and instead saw an expression react
const renderMyData = () => {
// groupedData is an array in the component made through useState()
const myData = groupedData.map((c, index) => {
return <MyCustomComponent key={index} data={c} />; It goes into the infinity loop
});
return myData;
};
Function is called like this in the component:
{renderMyData()}

Why is my state variables being rendered twice in reactjs

Every time I use react and the useEffect method my state variable renders twice. Once an empty variable and the next the desired variable. What can I try to help avoid this problem for now and in the future?
import React, { useState,useEffect } from "react";
export default function Member (props) {
const [team,setTeam] = useState([]);
useEffect(() => {
let array = ["hello","hi"];
setTeam(array);
}, [])
console.log(team);
return (
<>
{team.forEach(i => <p>{i}</p>)}
</>
)
}
You need to use map to render an array in JSX:
export default function Member(props) {
const [team, setTeam] = useState([]);
useEffect(() => {
let array = ["hello", "hi"];
setTeam(array);
}, []);
console.log(team);
return (
<>
{team.map(i => ( // use map here
<p>{i}</p>
))}
</>
);
}
forEach doesn't return anything, so you can't use it to render components like that.
Also in your code instead of using useEffect to setup initial state, you can just set it straight in useState:
export default function Member(props) {
const [team, setTeam] = useState(["hello", "hi"]);
console.log(team);
return (
<>
{team.map(i => ( // use map here
<p>{i}</p>
))}
</>
);
}
It is an abvious behavior.
Component render's first time with initial state. After useEffect (componentDidMount) again re-renders.
So you are getting two console.log.
To avoid this, you need to set the state initally,
const [team,setTeam] = useState(["hello","hi"]);
and remove useEffect.
Note: forEach won't print data, you need map here,
{team.map(i => <p key={i}>{i}</p>)} //provide a key here

Resources