How can I pass parameters from one function to another - reactjs

I am new to React and trying to figure something out. I have written the code below that should pass the values from one function to another and at the end accept parameters from an object to populate them. However, I can only see the text property of the nameInput object as an output. Please let me know what am I doing wrong?
import React, { Component } from 'react';
function FirstName(props){
return <h1>Hi, {props.fname.name}</h1>
}
function LastName(props) {
return (
<div className="UserInfo">
<FirstName fname={props.lname} />
<h2>{props.lname.name}</h2>
</div>
);
}
function FullName(props){
return (
<div className="container">
<LastName lname={props.fulname} />
<div>{props.text}</div>
</div>
);
}
const nameInput = {
name: {
firstname: 'Savi',
lastname: 'Dulai',
},
text: 'got it to work?'
};
class ComponentPractise extends Component {
state = { }
render() {
return (
<div className="row">
<FullName
text={nameInput.text}
fulname={nameInput.name}
/>
</div>
);
}
}
export default ComponentPractise;
I would like the output to say "Hi, Savi Dulai got it to work?".
Any help would be much appreciated.

Seem like you was lost the context. Function FullName is okay, but LastName and FirstName referenced to wrong props property.
import React, { Component } from 'react';
function FirstName(props){
return <h1>Hi, {props.fname.firstname}</h1>
}
function LastName(props) {
return (
<div className="UserInfo">
<FirstName fname={props.lname} />
<h2>{props.lname.lastname}</h2>
</div>
);
}
function FullName(props){
return (
<div className="container">
<LastName lname={props.fulname} />
<div>{props.text}</div>
</div>
);
}
const nameInput = {
name: {
firstname: 'Savi',
lastname: 'Dulai',
},
text: 'got it to work?'
};
class ComponentPractise extends Component {
state = { }
render() {
return (
<div className="row">
<FullName
text={nameInput.text}
fulname={nameInput.name}
/>
</div>
);
}
}
export default ComponentPractise;
It should works, but I recommend you to change review your function and variable naming to make it more readable.
Hope that helps!

You're close to the answer, it is just the matter of accessing the props properly. Your fulname prop is an object itself:
name: {
firstname: 'Savi',
lastname: 'Dulai',
}
Access it as props.fulname.firstname and props.fulname.lastname.
<!DOCTYPE html>
<html lang="en">
<title>myPage</title>
<script src= "https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src= "https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script src= "https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<body>
<div id="root"></div>
<script type="text/babel">
function FirstName(props){
return <h1>Hi, {props.fname}</h1>
}
function LastName(props) {
return (
<div className="UserInfo">
<h2>{props.lname}</h2>
</div>
);
}
function FullName(props){
return (
<div className="container">
<FirstName fname={props.fulname.firstname} />
<LastName lname={props.fulname.lastname} />
<div>{props.text}</div>
</div>
);
}
const nameInput = {
name: {
firstname: 'Savi',
lastname: 'Dulai',
},
text: 'got it to work?'
};
class ComponentPractise extends React.Component {
state = { }
render() {
return (
<div className="row">
<FullName
text={nameInput.text}
fulname={nameInput.name}
/>
</div>
);
}
}
ReactDOM.render(<ComponentPractise />, document.getElementById('root'));
</script>
</body>
</html>
Refactoring/suggestion
I'd suggest refactoring the code to this, you don't even need the two extra components if you do is this way!
<!DOCTYPE html>
<html lang="en">
<title>myPage</title>
<script src= "https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src= "https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script src= "https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<body>
<div id="root"></div>
<script type="text/babel">
function FullName(props){
return (
<div className="container">
<h2>Hi {props.fullname.firstname} {props.fullname.lastname}!</h2>
<div>{props.text}</div>
</div>
);
}
const nameInput = {
name: {
firstname: 'Savi',
lastname: 'Dulai',
},
text: 'got it to work?'
};
class ComponentPractise extends React.Component {
state = { }
render() {
return (
<div className="row">
<FullName
text={nameInput.text}
fullname={nameInput.name}
/>
</div>
);
}
}
ReactDOM.render(<ComponentPractise />, document.getElementById('root'));
</script>
</body>
</html>

You've made this example highly complex, but i guess you're just playing around. So am i:) Best thing to do is stick to one name for stuff you want to pass along. Also, you can console.log(props) above the return within functions to check what is being passed along.
import React, { Component } from "react";
function FirstName(props) {
return <h1>Hi, {props.firstname}</h1>;
}
function LastName(props) {
return (
<div className="UserInfo">
<FirstName firstname={props.nameObject.firstname} />
<h2>{props.text}</h2>
</div>
);
}
function FullName(props) {
return (
<div className="container">
<LastName nameObject={props.nameObject} />
<div>{props.text}</div>
</div>
);
}
const nameInput = {
name: {
firstname: "Savi",
lastname: "Dulai"
},
text: "got it to work?"
};
class ComponentPractise extends Component {
state = {};
render() {
return (
<div className="row">
<FullName text={nameInput.text} nameObject={nameInput.name} />
</div>
);
}
}
export default ComponentPractise;
Also, you can use IE6 syntax to clean things up a lot, since react parses it back into code all browsers can handle (IE6 JS isn't supported yet). Makes much nicer work. Also got rid of the functional component at the end.
import React from "react";
const FirstName = props => {
return <h1>Hi, {props.firstname}</h1>;
};
const LastName = props => (
<div className="UserInfo">
<FirstName firstname={props.nameObject.firstname} />
<h2>{props.text}</h2>
</div>
);
const FullName = props => (
<div className="container">
<LastName nameObject={props.nameObject} />
<div>{props.text}</div>
</div>
);
const nameInput = {
name: {
firstname: "Savi",
lastname: "Dulai"
},
text: "got it to work?"
};
export default () => (
<div className="row">
<FullName text={nameInput.text} nameObject={nameInput.name} />
</div>
);

Related

TypeError: author is undefined

creating react AuthorQuiz app
I have tow main file
1- AuthorQuiz.js
2- index.js
I have a problem with Turn component
AuthorQuiz.js
enter code here
function Turn({ author, books }) {
return (
<div className="row turn" style={{ backgroundColor: 'white' }}>
<div className="col-4 offset-1">
<img src={author.imageUrl} className="authorImage" alt="Author" />
</div>
<div className="col-6">
{books.map((title) => <p>{title}</p>)}
</div>
</div>);
}
function AuthorQuiz(turnData) {
return (
<div className="container-fluid">
<Hero/>
<Turn {...turnData}/>
<Continue/>
<Footer/>
</div>
);
}
index.js
enter code here
const authors = [
{
name: 'mark Twin',
imageUrl: 'images/authors/mark.jpg',
imageSource: 'google wiki',
books: ['The Advance of Finn']
}
];
const state={
turnData:{
author:authors[0],
books:authors[0].books
}
}
ReactDOM.render(<AuthorQuiz {...state}/>,
document.getElementById('root'));
but when I run my code I get an error
TypeError: author is undefined
Turn
C:/Users/HP/Desktop/React pro/authorquiz/src/AuthorQuiz.js:18
You should use {state.turnData} instead of {...state}.
Because the result of {...state} is like this: {turnData: {…}}
So { author, books } can't work correctly.
const state={
turnData:{
author:authors[0],
books:authors[0].books
}
}
<AuthorQuiz {...state}/>
Spreading the state over the AuthorQuiz is equivalent to:
<AuthorQuiz turnData={state.turnData}/>
But in the AuthorQuiz component:
function AuthorQuiz(turnData) {
return (
<div className="container-fluid">
<Hero/>
<Turn {...turnData}/>
<Continue/>
<Footer/>
</div>
);
}
function AuthorQuiz(turnData) {
...
<Turn {...turnData}/>
...
is equivalent to
function AuthorQuiz(props) {
...
<Turn turnData={
props.turnData
}}/>
...
So you need to add brackets to spread turnData instead of props:
function AuthorQuiz({ turnData }) {
...
<Turn { ...turnData}}/>
...
The AuthorQuiz component is getting the turnData variable as a prop. You should use the spread operator on the props.turnData variable instead.
function AuthorQuiz(props) {
return (
<div className="container-fluid">
<Hero/>
<Turn {...props.turnData}/>
<Continue/>
<Footer/>
</div>
);
}
The props in the AuthorQuiz component look like this:
{
turnData: {
author: { .. },
books: [ .. ]
}
}
Your Turn component wants the author and books props, so you could do this in your AuthorQuiz component.
function AuthorQuiz(props) {
return (
<div className="container-fluid">
<Hero/>
<Turn {...props.turnData} />
{/* or */}
<Turn author={props.turnData.author} books={props.turnData.books} />
<Continue/>
<Footer/>
</div>
);
}
You could also destructure the turnData prop in your component function directly. This makes it clear which props are being drilled down the Turn component without switching to multiple files.
function AuthorQuiz({ turnData: { author, books } }) {
return (
<div className="container-fluid">
<Hero/>
<Turn author={author} books={books} />
<Continue/>
<Footer/>
</div>
);
}

How to render multiple component in reactjs, what i'm doing wrong?

First i have a function to fetch data from database then
if the data be changed, i will create list components.
but it didnt work, what i'm doing wrong?
console:
class TweetContainer extends React.Component{
constructor(props){
super(props);
this.state = {
tweetData:{},
tweetRender : [],
listTweet:[]
}
}
here is my function to fetch data from database
componentDidMount(){
fetch('http://localhost:5000/tweet')
.then(function(response) {
return response.json();
})
.then(result=>{
this.setState({
tweetData: result
}, ()=>console.log(this.state.tweetData));
});
}
my function to make list component
componentDidUpdate(){
this.state.tweetRender = this.state.tweetData.data.slice(1,6);
console.log(this.state.tweetRender);
this.state.listTweet = this.state.tweetRender.map((tweet)=><Tweet
linkAvatar={'/image/jennyshen.jpg'}
name={"Vuongxuan"}
userName={'#vuggg'}
tweetText={tweet.content} />);
console.log(this.state.listTweet);
}
render(){
return(
<div id="main">
<h2>Tweet</h2>
<div id="stream">
{this.state.listTweet}
</div>
</div>
);
}
}
i dont know what i'm doing wrong.
Accordingly to React docs, componentDidMount lifecycle most common use is for:
Updating the DOM in response to prop or state changes.
And you want to get and render the tweets, right? Not necessarily listen to updates.
For now a solution is remove your componentDidUpdate() method and change your `render´ method to:
render(){
var tweetRender = this.state.tweetData.data.slice(1,6);
return(
<div id="main">
<h2>Tweet</h2>
<div id="stream">
{listTweet.map((tweet, idx) =>
<Tweet
key={idx}
linkAvatar={'/image/jennyshen.jpg'}
name={"Vuongxuan"}
userName={'#vuggg'}
tweetText={tweet.content} />
)}
</div>
</div>
);
}
It's generally not a good idea to put React elements (JSX) inside your component state. You could instead just store the data in state, and derive the JSX from that data in the render method.
Example
class TweetContainer extends React.Component {
state = {
tweetData: [],
tweetRender: [],
listTweet: []
};
componentDidMount() {
setTimeout(() => {
this.setState({
tweetData: [
{
id: 1,
name: "foo",
username: "#foo"
},
{
id: 2,
name: "bar",
username: "#bar"
}
]
});
}, 1000);
}
render() {
return (
<div id="main">
<h2>Tweet</h2>
<div id="stream">
{this.state.tweetData.map(obj => (
<div key={obj.id}>
{obj.username} - {obj.name}
</div>
))}
</div>
</div>
);
}
}
ReactDOM.render(<TweetContainer />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

React img tag add class on load

I am using React. I have a list of images:
<div className="Images-gridWrapper">
{this.props.images.map((item, index) => {
return (
<div className="Images-gridItem" data-id={index} key={index}>
<img className="Images-gridImage" src={item.img.w1200}
onLoad={(e)=>{
// HERE
}}
/>
</div>
);
})}
</div>
I am looking for a way to add a class to each img tag when its image is loaded. I suppose that the onLoad function is the correct way, but how?
You can create a new component Img that has a state variable that you set to true when the image has been loaded. You can then use this state variable to add the additional class to the img element.
Example
class App extends React.Component {
render() {
return (
<div className="Images-gridWrapper">
{this.props.images.map((item, index) => {
return (
<div className="Images-gridItem" data-id={index} key={index}>
<Img src={item} />
</div>
);
})}
</div>
);
}
}
class Img extends React.Component {
state = { loaded: false };
onLoad = () => {
this.setState({ loaded: true });
console.log("Loaded!");
};
render() {
const { loaded } = this.state;
return (
<img
className={"Images-gridImage" + (loaded ? " Images-gridImage-loaded" : "")}
src={this.props.src}
onLoad={this.onLoad}
/>
);
}
}
ReactDOM.render(
<App
images={[
"http://placekitten.com/100/100",
"http://placekitten.com/100/200"
]}
/>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Render a string which contains components

I am newbie at reactJs and i am trying to build an app in which i get some results after searching .
My problem is that i have a component called ResultEntity and I am trying create a dynamically page without defined number of ResultEntity components.
I tried something like this
for(var i=0 ; i<result.length ; i++)
{
results += "<div> <ResultEntity/> </div>";
};
console.log(results);
this.setState({result: results});
And i tried to return it like ,
return (
<div>
<div dangerouslySetInnerHTML={{ __html: this.state.result }} />
</div>
);
and
return (
<div>
<div dangerouslySetInnerHTML={{ __html: this.state.result }} />
</div>
);
but both didnt work . Any idea will be appreciated . Thank you in advance
So you want to render a list of components dynamically. Here's how you can do it using .map function:
// This also can be a functional component, instead of a class
class ResultEntity extends React.Component {
render() {
const { item } = this.props
return <div>{ `${item.id} - ${item.name}` }</div>
}
}
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
items: [
{ id: 1, name: 'Bulgaria' },
{ id: 2, name: 'Germany' },
]
}
}
renderItems() {
const { items } = this.state
// Great explanations, why this work and it's rendered correctly:
// https://medium.com/byte-sized-react/component-arrays-in-react-a46e775fae7b
return items.map(item => <ResultEntity key={item.id} item={item} />)
}
render() {
// From React >= 16 it's possible to skip the wrapper `div`:
// https://stackoverflow.com/a/32157488/4312466
return <div>{ this.renderItems() }</div>
}
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>

Is the correct way to access ref in react?

Without using binding of this.say to this on button the example does not work. However I am not sure if it is right or has any side effects.
class Speak extends React.Component {
render() {
return (
<div>
<input ref={(c) => this._input = c} defaultValue="Hello World!"/>
<button onClick={this.say.bind(this) }>Say</button>
</div>
);
}
say() {
if (this._input !== null) {
alert(this._input.value);
}
}
};
ReactDOM.render(<Speak />, document.getElementById('App'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="App" />
Seems like this is required when using ES6 classes: See: Autobinding
Only difference is example above binds the method in constructor
you can utilize array functions and forget about adding .bind(this)
check out working pen
class Speak extends React.Component {
render() {
return (
<div>
<input type='text' ref='greeting'/>
<button onClick={this.say}>Say</button>
</div>
);
}
say = () => {
const { value } = this.refs.greeting;
alert(value);
return value;
};
};
ReactDOM.render(<Speak />, document.getElementById('App'));

Resources