Passing back the result of a this.props.functionName() to parent - javascript

In React JS I have 2 files:
File 1: Chat.js
This file calls numerous custom components and provides them with custom functions as props.
File 2: PreviewChatBox.js
This file shows a preview of multiple chats. When I call the function that has been sent from chat.js (load Chat) it changes a state in Chat.js to an integer from one of the previewchat components.
I need to be able to access that component in Chat.js but I can't seem to be able to pass the variable back.
CODE:
File 1: Chat.js
render(){
return(
<PreviewChatBox onClicked={() => this.previewClicked()}/>
)}
File 2: PreviewChatBox.js
<div onClick={() => this.props.onClicked()} key={value}>
<p> {element[0]}{element[1]}{element[2]} </p>
</div>
So I can call the method without any problem but I cannot pass the key back to chat.js

Have you looked into using a callback function?
Chat.js
<PreviewChatBox
onClicked={() => this.previewClicked()}
updateKey((newKey) => this.setState({newKey}) />
Now your child component should be able to update the state of Chat.js by accessing the updateKey function from props.

Hope this helps match your use case, but I'm able to get this working by referencing the previewClicked method directly in Chat.js without using an arrow function and passing the key directly to the onClick behavior in PreviewChatBox.js
File 1 : Chat.js
previewClicked = (val) => {
console.log(val);
};
render() {
return (
<PreviewChatBox onClicked={ this.previewClicked }/>
)
};
File 2 : PreviewChatBox.js
const element = ['abc','def','ghi'];
const value = 2;
return (
<div onClick={ () => props.onClicked(value) } key={value}>
<p> {element[0]}{element[1]}{element[2]} </p>
</div>
);

Related

How to use a HTML portion of a react.js file to another react.js file

I am trying to use the content of a separate react.js file to another react.js file. The js file contains a drop down & the drop down i want to show on the basis of a condition. Below is the js file which contains the drop down
const MyDataTableHeader = ({
first =0,
pageSize=0,
totalElements=0,
exportFile,
})
....
return(
<div className="someCss">
<Dropdown style={{width:100%, textAlign : "center"}}
value={selectedFileFormat}
options = {downloadOptions}
placeholder="Export As"
id={DOWNLOAD_OPTION}
name={DOWNLOAD_OPTION}
onChange={(e) => {
setSelectedFileFormat(e.value);
}}
/>
</div>
<div style={{padding:"1em"}} className = "someCss1">
<Button type="button" icon = "pi pi-download" iconPos="left" onClick={exportHandler}
/>
This portion of the code displays a Drop Down and a option to export, i want to use this code block within another js file , below is the content of the js file
const MySearchPanel = ({onSearch,onClear,exportFile }) =>
const searchHandler = () => {
if(//some Condition){
// i want to show the Drop down with export option here
You want to export your dropdown as a component and then inside your other file inside your condition you just render it using JSX.
import Dropdown from "../from/another/file" // const DropDown = require('from another file') if you do not wish to use module syntax.
const MySearchPanel = ({onSearch,onClear,exportFile }) =>
const searchHandler = () => {
// ...
return (
//if the codition is true show dropdown otherwise show nothing
<div>
{Condition ? <Dropdown /> : null }
</div>
);
// ...
I hope this answers your question.

How to inject a dinamically created element into an existing div in React JSX?

I have a list of objects photos, from a json data file, that I would like to organize into 3 different <div> columns, but I dont know how to achieve that, here is my broken non-optimized code:
<div className="container">
<div ref={leftColRef} className="left-col" />
<div ref={centreColRef} className="centre-col" />
<div ref={rightColRef} className="right-col" />
{Object.keys(photos).forEach((n, i) => {
const id = photos[n].id;
const thumb = photos[n].thumbnailUrl;
const title = photos[n].title;
const element = (
<Thumbnail id={id} title={title} thumb={thumb} />
);
if (i % 3 === 0) {
leftColRef.current.append(element);
} else if (i % 3 === 1) {
centreColRef.current.append(element);
} else {
rightColRef.current.append(element);
}
// this line works, it idsplays the data but is commented as the data needs to go inside its respective columns
// return <Thumbnail key={id} title={title} thumb={thumb} />;
})}
</div>
The idea is to insert some elements into the left-column when i%3 = 0 and others in the centre-column when i%3 = 1 and so on ...
And a link to my codesandbox
Any help/advise will be much appreciated.
Easiest is probably to prepare the data outside the render function and to render the column one by one.
You should not manipulate the DOM like it's done in jQuery using JSX
Example:
const Component = (props) => {
const filterPhotos = (column) => {
return props.photos.filter((photo,index)=> index%3==column);
}
return <>
<MyColumn photos={filterPhotos(0)}/>
<MyColumn photos={filterPhotos(1)}/>
<MyColumn photos={filterPhotos(2)}/>
</>;
}
First, using ref on div to inject stuff on it is wrong. It's the opposite of how react works.
Like charlies said, I would split the photos in 3 different arrays before the render. Then, you'll be able to do something like this :
<div ref={leftColRef} className="left-col" />
{ photosLeft.map(photo => <Thumbnail key={photo.id} {...photo} />)
</div>
when preparing your data, try to use the same object properties and component props name so you can spread it easily ( {...photo} ).
Note: Also, when rendering an array in react, each child must have a unique key props. It will help react to render on that part of dom if your data change.

Declaring function inside class component vs inside functional component

I am playing with function syntax inside and outside class components. Can anyone explain to me why the print function works when written like this
const UploadButton = (props)=> {
const fileName = 'myfile';
props.getFileName(fileName)
function print(){console.log('onClick worked')}
return(
<div>
<input onClick= {print()} type="file" id = {fileName}/>
</div>
)
}
but when i write it like i would when declaring it inside a class component:
print(){console.log('onClick worked')}
i get this error
Line 10: Parsing error: Unexpected token, expected ";"
8 | props.getFileName(fileName)
9 |
> 10 | print(){console.log('onClick worked')}
| ^
This behavior is not tied with React but fundamentally is a method vs. function thing in JavaScript.
When you declare functions with some context it becomes a method. So, In a class setup, the functions are actually methods.
In Javascript, it is possible to declare a function within another function, that is why this works
const UploadButton = (props)=> {
const fileName = 'myfile';
props.getFileName(fileName)
function print(){console.log('onClick worked')}
return(
<div>
<input onClick= {print()} type="file" id = {fileName}/>
</div>
)
}
But when you don't specify the function keyword and the declaration is not inside of class it throws error.
print(){console.log('onClick worked')}
Parsing error: Unexpected token, expected ";"
If you rather used an arrow function here print=()=>{console.log('onClick worked')}, it would work because its a function expression and is treated as a normal variable declaration scoped to the enclosing function.
print(){console.log('onClick worked')}
I think when you write this in a functional component the compiler does not know that you are trying to define a function and it is rather trying to execute the print function, hence it is expecting a ';'
However, In class based components when you define a function using the above syntax, when the class is converted to a function, the print method will be added to its prototype.
One issue that you're having with your functional component is that you're calling the print function, then passing whatever it returns, which is undefined in this case, to the onClick handler of your input element.
Your JSX for the input element should look like this:
const UploadButton = (props)=> {
// ...
return (
<div>
<input onClick={print} type="file" id={fileName}/>
</div>
)
}
When dealing with class components, however, your UploadButton component, should look like the following:
class UploadButton extends React.Component {
print() {
console.log('onClick worked')
}
render() {
// ...
this.props.getFileName(fileName)
return (
<div>
<input onClick={this.print} type="file" id = {fileName}/>
</div>
)
}
}
Also, you probably shouldn't be using an input element as your UploadButton. Just use a button element instead, something like the following example:
<form>
<div>
<label for="file">Choose file to upload</label>
<input type="file" id={fileName} />
</div>
<div>
<!--Should be something along the lines of `this.handleSubmit`
rather than `this.print`, but you get the idea-->
<button onClick={this.print}>Submit</button>
</div>
</form>

React Child Component Loop not redenring

Well I have one of the views from my single page application that is a Quiz, But when a click to generate the Components through a loop based on information on my array state he doesn't render it. I'm using react-router in the index.js maybe this information can help.
Gabarito.js
return(
<div>
<h1 className="display-1">Resposta-#{this.props.chave}-
{this.props.alternativa}</h1>
</div>);
Quiz
state = {
respostas:[10],
gabarito:['Verdadeiro','Falso','Falso','Verdadeiro','Verdadeiro','Falso','Verdadeiro','Falso','Verdadeiro','Verdadeiro'],
correcao:[],
novogabarito: this.eachcomponent
}
alterarevento = (evento,index) =>{
let array = this.state.respostas;
array[index] = evento.target.value;
this.setState({respostas:array});
console.log(this.state.respostas[index])
}
gerargabarito = () =>{
for(let n=0;n<10;n++){
if(this.state.respostas[n]===this.state.gabarito[n]){
this.state.correcao.push('Certa');
}
else{
this.state.correcao.push('Errada');
}
}
console.log(this.state.correcao);
}
eachcomponent = () =>{
return(this.state.correcao.map(resposta=><Gabarito chave={this.state.correcao.indexOf(resposta)} alternativa={resposta}/>));
}
Render of function
<div className="row justify-content-center">
<span id="teste">{this.state.novogabarito}</span>
</div>
</div>
);
}
}
Perhaps I am overlooking something...but it does not look like you are ever invoking your alterarevento and gerargabarito functions. So when you call your eachcomponent your correcao array in your state is still empty so you are not mapping anything.
Before your return statement in your eachcomponent function, try logging correcao to the console to see if it is empty.
A word of caution: you should never manipulate your state directly. So, your this.state.correcao.push('Certa');
line should be:
this.setState({ correcao: [...this.state.correcao, 'Certa'] });

Can you use jsx within template string in React render props?

Is it possible to put JSX inside a template string that is being used as a React render prop?
This is what I'm trying to do, but it leads to the link rendering as [object Object]
const Container = ({ message }) => <div className="from line 4"> {message}</div>;
const Link = () => juan;
const App = () => (
<div>
<Container message={`My message with a ${<Link />}`} />
</div>
);
One thing I tried was to put JSX instead of a template string inside message. This works, but it introduces a new div that isn't needed.
<Container
message={<div>My message {<Link />}</div>}
/>
I made this codesandbox to illustrate the problem
You can use a Fragment to render inline like you are trying to do and to prevent adding a new wrapping <div />:
const App = () => (
<div>
<Container
message={<React.Fragment>My message with a <Link /></React.Fragment>}
/>
</div>
);
Here is a forked version of your Codesandbox using React.Fragment: https://codesandbox.io/s/nrmr9l34vl

Categories