I'm trying to pass props from my Parent component to child component. Here are the important snippets:
Snippet 1: This is the object that contains the prop (integer).
const cardProps = {
cardProps0: 0,
Snippet 2: This is the Card component within the parent component that carries the prop to child component
return (
<MyCardLink source={cardProps.cardProps0} />
Snippet 3: This is the child component (MyCardLink)
useEffect((props) => {
axios
.get(
'http://newsapi.org/v2/everything?q=economy&apiKey=XXXXXXXXXXXXXXXX'
)
.then((res) => {
console.log(res);
setNews(res.data.articles[props.source]);
})
.catch((err) => {
console.log(err);
});
}, []);
The goal is that [prop.source] contains a number value from a list of an array served by an API. If I just place a number value in the child component (MyCardLink) in place of [props.source] on the setNews function then it renders the component no problem.
My problem is when I pass the prop from parent component to child component and use [prop.source], nothing renders and all I get from the console log is:
Cannot read property 'source' of undefined.
Am I doing something wrong?
Instead of passing props into your useEffect, you need to add into your MyCardLink component's parameters as:
const MyCardLink = (props) => {
// your component's defintion
}
Additionally you can destructure as the following:
const MyCardLink = (props) => {
const { source } = props
// ... rest
}
Then simply you can use in your useEffect without props as:
useEffect(() => {
axios.get(
'http://newsapi.org/v2/everything?q=economy&apiKey=XXXXXXXXXXXXXXXX'
)
.then((res) => {
console.log(res);
setNews(res.data.articles[source]);
})
.catch((err) => {
console.log(err);
}
);
}, []);
Based on your other question from the comment section what I would do is:
Change the initial value of the state from "" to null as const [news, setNews] = useState(null).
Also I would use && for null check and render <Card /> component only if it has value as news && <Card className={classes.root}> in your return.
The reason behind this is your API response is arriving asynchronously.
use use props in component below:
const MyCardLink =(props)=>{
...
...
...
}
export default MyCardLink;
Related
I have a react child component (FinalReport.js) that is rendering twice, except that on the first render, one of the props is undefined for some reason, which is throwing an error. Of course I could add error handling but that doesn't seem like best practice.
The Parent Component contains user inputs which are saved as a useState Hook (esrData) upon pressing a 'Save' button. The first child component (Airload.js) contains more inputs and calls an API, and saves the result as a useStateHook (airLoadRes). Both hooks are defined in the parent component and passed as props. The child component in question (FinalReport.js) ONLY renders once both hooks become available, and then passes the hooks along. Why is FinalReport rendering twice and why is airLoadRes undefined on the first render? Strict Mode is not being used. Any help is appreciated!
Parent Component
const GenerateEnergySavings = () => {
const [esrData, setEsrData] = useState();
const [airLoadRes, setAirLoadRes] = useState();
...
return( ...
// Child Component 2
{(esrData && airLoadRes != undefined) ?
<PDFViewer height='1000px' width='1000px'>
<FinalReport esrData={esrData} airLoadRes={airLoadRes} />
</PDFViewer> : ''}
...
// Child Component 1 (API)
<Airload airLoadRes={airLoadRes} setAirLoadRes={setAirLoadRes} />
Child Component 1
EDIT: I should mention this is a bootstrap modal
const Airload = ({ airLoadRes, setAirLoadRes }) => {
...
// Airload API
const getAirLoadCalc = async () => {
console.log(airloadData)
await Axios.post('https://localhost:44418/airload', airloadData)
.then(res => {
setAirLoadRes(res.data)
console.log(res)
setKey(6)
}).catch(err => {
alert(err)
})
}
}
Child Component 2
// This is rendering twice!! ONLY airLoadRes comes in as undefined on first render
export const FinalReport = ({ esrData, airLoadRes }) => {
console.log(esrData)
console.log(airLoadRes)
...
This code (const [airLoadRes, setAirLoadRes] = useState();) initialize airLoadRes as undefined.
That's why it is undefined on first render.
React does render on each change of the state, context, or properties. So, I guess FinalReport is rendered twice because of changes on esrData state. Or other state which you possibly have in the code.
Hi developers I'm just a beginner in React.js. I tried to print props by passing from parent to child.
This is app.js file
import React from "react";
import Hooks from "./components/ReactHooks1";
import Hooks2 from "./components/ReactHooks2";
const App = () => {
return (
<div>
<h1>
Welcome to React App
</h1>
<Hooks2 title2={"Welcome"}/>
</div>
)
}
export default App
This is child component file
import React from 'react';
const Hooks2 = (props) => {
console.log(props);
}
export default Hooks2;
I just try to print props but it shows an empty object. what am I doing wrong please help me on this
You should return something or null to parent component from child, when you're using it in parent component. This will solve your problem
export const Hooks2 = (props) => {
console.log(props);
return <></>;
}
#Rasith
Not sure why would you want to do this, but if you're trying to pass a child component that would print something to the console. In this case you need to destructure the component's props. Here's an article about it from MDN.
This is how I would do it:
const CustomComponent = ({title}) => {
console.log(title)
}
const App = () => {
return (
<>
<h1>Hello World</h1>
<CustomComponent title={"Welcome"}/>
</>
);
};
For the title to be printed to the console, no need to add a return statement to the child component. Again, not sure why you would do this, but there you go.
Well trying to console.log title certainly would not work because what you are passing is called title2. Also your child component is not returning anything.
First, you have to return anything from your child component( even a fragment )
You can access title2 in the child component with any of these methods:
1- using props object itself
const Hooks2 = (props) => {
console.log(props.title2);
return;
}
2- you can also destructure props in place to access title2 directly
const Hooks2 = ({title2}) => {
console.log(title2);
return ;
}
You have to use destructuring in your ChildComponent, to grab your props directly by name:
const Hooks2 = ({title2}) => {
console.log(title2);
}
You can read a little bit more about it in here: https://www.amitmerchant.com/always-destructure-your-component-props-in-react/
I've been refactoring a small application that was initially within one file into it's own separate components. Currently I have a child component UsersTable that I am rendering within the parent Users2. I am passing some dummy data from the parent as props to the child but am getting the lovely Cannot read property 'map' of undefined.
I am using react hooks and passing props with the spread operator in the parent:
<UsersTable {...columns} {...data} />
And the child is receiving that here:
export const UsersTable = props => {
const [usersState, setUsersState] = useState(props)
useEffect(() => {
setUsersState(props)
}, [props])
const renderUsers = () => {
if (usersState) {
return usersState.map(d => items(d))
} else {
return noData
}
}
As well as down in the return function here:
<ActionList columns={usersState}>{renderUsers}</ActionList>
I am specifically trying to figure out why the data prop (an array of objects), is returning undefined. Linking my sandbox here. I wondering if the issue is perhaps related to passing multiple separate props via spread operators.
Any help or advice around what I am trying to accomplish would be much appreciated!
That's not a correct way to pass down props.
Props are passed as properties of an object and hence you need to define a name and value to it.
For ex, you need to write,
<UsersTable {...columns} {...data} />
as
<UsersTable columns={columns} data = {data} />
Now the UserTable component will get this props object,
props = {
columns=the column data,
data = the data
}
To use this props, you can use destructuring
const {data, columns} = props;
or you can use the dot notation,
props.column & props.data
You need to pass by attribute
<UsersTable columns={...columns} data={...data} /> /*<-- Changes */
export const UsersTable = props => {
const [usersState, setUsersState] = useState(props)
useEffect(() => {
setUsersState(props)
}, [props])
const renderUsers = () => {
if (usersState) {
return usersState.map(d => items(d))
} else {
return noData
}
}
<ActionList columns={usersState}>{renderUsers}</ActionList>
In User2 component, import UsersTable component need change from this:
<UsersTable {...columns} {...data} />
to this:
<UsersTable columns={columns} data={data} />
And in UserTable component you need to change:
const [usersState, setUsersState] = useState(props)
to:
const [columns, setColumns] = useState(props.columns)
const [users, setUsers] = useState(props.data)
renderUsers will be:
const renderUsers = () => {
if (users) {
return users.map(d => items(d))
} else {
return noData()
}
}
And last, import ActionList component like this:
<ActionList columns={columns}>{renderUsers()}</ActionList>
After that, UsersTable component will working fine.
Parent Component:
<UsersTable columns={columns} data={data} />
See my github for an example of how to use hooks and props in a similar way:
https://github.com/RyanJMorris11/helloReactHooks/blob/master/src/components/userList.js
I am trying to access my prop "post" from my parent. I can access it inside render(), but not above where I have my getCom(). How can I make the prop available in functions and not only in the render? I tried to use this.item.id.bind(this), but that does not work.
Parent:
<LoadComments post={item.id}/>
Child
class LoadComments extends Component {
getCom = async () => {
// Thid does not work
this.unsubscribe = await firestore.collection("comments").where("post", "==", this.props.post).onSnapshot((querySnapshot) => {
// Rest of code
}
render() {
return (
// This works:
{this.props.post}
)
}
To use the value of
item.id
in your child component what you should do is:
In Parent:
<LoadComments post={item.id}>
In Child Component:
class LoadComments extends Component {
async getCom(props) => {
// This would work now
this.unsubscribe = await firestore.collection("comments").where("post", "==",
props.post).onSnapshot((querySnapshot) => {
// Rest of code
}
render() {
const props = this.props;
return (
{this.props.post}
getCom(props)
)
}
You have to store the props in a static component in render method and then pass the props to the function declared outside the render method.
As you see you pass id as post to your child component :
<LoadComments post={item.id}/>
so you must use this :
this.props.post
if you want to use id you must pas it as id like this :
<LoadComments id={item.id}/>
I have a seemingly trivial question about props and function components. Basically, I have a container component which renders a Modal component upon state change which is triggered by user click on a button. The modal is a stateless function component that houses some input fields which need to connect to functions living inside the container component.
My question: How can I use the functions living inside the parent component to change state while the user is interacting with form fields inside the stateless Modal component? Am I passing down props incorrectly?
Container
export default class LookupForm extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false
};
}
render() {
let close = () => this.setState({ showModal: false });
return (
... // other JSX syntax
<CreateProfile fields={this.props} show={this.state.showModal} onHide={close} />
);
}
firstNameChange(e) {
Actions.firstNameChange(e.target.value);
}
};
Function (Modal) Component
const CreateProfile = ({ fields }) => {
console.log(fields);
return (
... // other JSX syntax
<Modal.Body>
<Panel>
<div className="entry-form">
<FormGroup>
<ControlLabel>First Name</ControlLabel>
<FormControl type="text"
onChange={fields.firstNameChange} placeholder="Jane"
/>
</FormGroup>
);
};
Example: say I want to call this.firstNameChange from within the Modal component. I guess the "destructuring" syntax of passing props to a function component has got me a bit confused. i.e:
const SomeComponent = ({ someProps }) = > { // ... };
You would need to pass down each prop individually for each function that you needed to call
<CreateProfile
onFirstNameChange={this.firstNameChange}
onHide={close}
show={this.state.showModal}
/>
and then in the CreateProfile component you can either do
const CreateProfile = ({onFirstNameChange, onHide, show }) => {...}
with destructuring it will assign the matching property names/values to the passed in variables. The names just have to match with the properties
or just do
const CreateProfile = (props) => {...}
and in each place call props.onHide or whatever prop you are trying to access.
I'm using react function component
In parent component first pass the props like below shown
import React, { useState } from 'react';
import './App.css';
import Todo from './components/Todo'
function App() {
const [todos, setTodos] = useState([
{
id: 1,
title: 'This is first list'
},
{
id: 2,
title: 'This is second list'
},
{
id: 3,
title: 'This is third list'
},
]);
return (
<div className="App">
<h1></h1>
<Todo todos={todos}/> //This is how i'm passing props in parent component
</div>
);
}
export default App;
Then use the props in child component like below shown
function Todo(props) {
return (
<div>
{props.todos.map(todo => { // using props in child component and looping
return (
<h1>{todo.title}</h1>
)
})}
</div>
);
}
An addition to the above answer.
If React complains about any of your passed props being undefined, then you will need to destructure those props with default values (common if passing functions, arrays or object literals) e.g.
const CreateProfile = ({
// defined as a default function
onFirstNameChange = f => f,
onHide,
// set default as `false` since it's the passed value
show = false
}) => {...}
just do this on source component
<MyDocument selectedQuestionData = {this.state.selectedQuestionAnswer} />
then do this on destination component
const MyDocument = (props) => (
console.log(props.selectedQuestionData)
);
A variation of finalfreq's answer
You can pass some props individually and all parent props if you really want (not recommended, but sometimes convenient)
<CreateProfile
{...this.props}
show={this.state.showModal}
/>
and then in the CreateProfile component you can just do
const CreateProfile = (props) => {
and destruct props individually
const {onFirstNameChange, onHide, show }=props;