Conditional Rendering of Props (no re-render) - javascript

I am importing some mock data which is organised as an array in productData.js. This is being passed as a prop into TableComponent. However, if conditional rendering is not used (props.productData && ...) I get Cannot read property 'map' of undefined. From my reading, this is because render is called before the props are received asynchronously.
However, with the example below, the page is re-rendered when productData is imported. I have checked in the React Developer Tool and TableComponent does contain props.ProductData which is the array just as I expected.
Why does the page not re-render with the data?
import productData from './productData.js'
...
const MainBody = () => {
return (
<TableComponent>
productData={productData}
</TableComponent>
);
}
const TableComponent = props => {
const rows = props.productData && props.productData.map((row, index) => {
return (
<tr>
<row>{row}</row>
</tr>
);
});
return <tbody>{rows}</tbody>

<TableComponent>
productData={productData}
</TableComponent>
thats a TableComponent with no props and a text inside saying productData={productData}. You probably wanted:
<TableComponent productData={productData} >
</TableComponent>

Related

React Component rendering twice, props 'undefined' at first render

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.

Props are not passing from parent to child components in React Functional component

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/

Passing props to UseEffect hook from Parent component

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;

Why this error is showing: "A valid React element (or null) must be returned. You may have returned undefined"

I know this question has been answered but i just cannot handle what's going so wrong. I'm having a wrapper function:
const withTracker = (WrappedComponent, partnerTrackingCode, options = {}) => {
const trackPage = (page) => {
ReactGA.set({
page,
options
});
ReactGA.pageview(page);
};
class HOC extends Component {
componentDidMount() {
ReactGA.initialize(partnerTrackingCode);
const page = this.props.location.pathname;
trackPage(page);
}
componentWillReceiveProps(nextProps) {
const currentPage = this.props.location.pathname;
const nextPage = nextProps.location.pathname;
if (currentPage !== nextPage) {
trackPage(nextPage);
}
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return HOC;
};
export default withTracker;
and i'm calling it here:
export default (props) => {
const MainComponent = (
<div>
...
</div>
);
if (props.partnerTrackingCode) {
return (
withTracker(MainComponent, props.partnerTrackingCode)
);
}
return (<div />);
};
When the tracking code is defined and the withTracker is called even if mainComponent is a component it shows me this error: A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object
I've also try to replace the WrappedComponent with an empty div:
return(<div />)
but still the same error
It looks like you're confusing elements and components here. You're passing around elements (the actual output you want to be rendered), whereas a HOC is a component (a function that generally takes a set of props and returns an element). You're passing an element to your HOC, so when it tries rendering it (in the HOC render function) it can't render it and you get the error.
To fix, you'd firstly need to make your MainComponent into an actual component instead of just the element you want it to return, e.g.:
const MainComponent = props => (
<div>
...
</div>
)
Then to use that with your wrapper you'd want to wrap and then render that:
if (props.partnerTrackingCode) {
const MainWithTracker = withTracker(MainComponent, props.partnerTrackingCode)
return <MainWithTracker />;
}
This is a bit weird though, as you need to create the wrapped component within your render method, which isn't how you'd normally do things. It might make more sense to change your HOC so that it returns a component that takes the partnerTrackingCode as a prop instead of an argument to your HOC. Something along the lines of:
// your HOC (omitting irrelevant bits)
const withTracker = (WrappedComponent, options = {}) => {
...
class HOC extends Component {
componentDidMount() {
ReactGA.initialize(this.props.partnerTrackingCode);
...
}
...
render() {
// pull out the tracking code so it doesn't get passed through to the
// wrapped component
const { partnerTrackingCode, ...passthrough } = this.props;
return <WrappedComponent {...passthrough} />;
}
}
return HOC;
};
// in your component
const MainComponent = props => (
<div>
...
</div>
);
const MainWithTracker = withTracker(MainComponent);
export default (props) => {
if (props.partnerTrackingCode) {
return (<MainWithTracker partnerTrackingCode={props.partnerTrackingCode} />);
}
return (<div />);
};
(I don't think this is the best way to do it, I've just tried keeping as close to your code as I could. Once you start restructuring it, with your better knowledge of exactly what you're trying to do you may find a better way to organise it.)
your problem in your return method , in first step you must be know
when you want call HOC , you must write like this
return withTracker(MainComponent, props.partnerTrackingCode)
instead this
return (
withTracker(MainComponent, props.partnerTrackingCode)
);
remove ()
and then check again , if you still have error tell me

React children throw PropTypes error

I'd like to know, how to handle the PropTypes Error when passing a component as a child:
Failed prop type: The prop `value` is marked as required in `ChildComponent`, but its value is `undefined`.
The render works as expected and it's passing the value prop correctly.
I suppose this happens because I am putting the component in the App component's render function without any props.
I am only passing those props to the ChildComponent when the ParentComponent maps over its children (which is the ChildComponent).
See the code: https://codesandbox.io/embed/r70r5z3j9q
Is there a way to prevent this from happening?
How should I be structuring my components?
Am I not supposed to passed components as children?
EDITED: Changed prop "name" to "value". To give it a more generic feel.
I tried to simplify the problem in the code.
I know I could pass the prop directly in App.
The use case would be when the parent is doing calculations and those calculations are supposed to be passed to the child. Without explicitly knowing what these children are.
That's why I'm using it as child in the first place.
You're using cloneElement and you're passing prop to it, not to original element. To fix it, pass props directly:
const App = () => (
<div>
<ParentComponent>
<ChildComponent name="bob" />
</ParentComponent>
</div>
);
You could easily pass component as a prop (not children) to you ParentComponent and render it only after it takes some heavy calculations:
const App = () => (
<div>
<ParentComponent component={ChildrenComponent} />
</div>
);
const ParentComponent extends React.Component {
state = { heavyComputationFinished: false } // initial state
componentDidMount() {
runYourHeavyComputations
.then(() => { this.setState({ heavyComputationsFinished: true }) })
}
render() {
const { component } = this.props
const { heavyComputationsFinished, name } = this.state
// return nothing if heavy computations hasn't been finished
if (!heavyComputationsFinished) { return null }
// we're getting this component (not its rendering call) as a prop
return React.render(component, { name })
}
}

Categories