Passing data from parent class to child function -props undefined - javascript

I'm trying to pass data 'template_titles' to my child component and display them in an option dropdown. Just trying to console.log the data to make sure it's passing. Currently running into an issue where property props are undefined.
Parent Component
render() {
if (!this.props.show) {
return null;
}
const template_titles = this.state.email_template.map((a) => a.title);
console.log(template_titles);
return (
<div className='compose-email'>
<div className='directory'>
<div className='background' />
<div className='box'>
<ion-icon
id='close-email'
name='close'
onClick={this.onClose}
></ion-icon>
<ion-icon
id='square-email'
name='square'
onClick={this.onClose}
></ion-icon>
<h1 className='candidate-name-compose-email'>
Candidate Name
</h1>
<hr></hr>
<h1 className='compose-email-title-compose-email'>
Compose Email
</h1>
<ComposeEmailForm
handleCompose={this.sendNewEmail}
template_titles={this.template_titles}
/>
</div>
<ToastContainer className='toast-container' />
</div>
</div>
);
}
Child Component
export default function ComposeEmailForm({ handleCompose }) {
console.log(this.props.template_titles);
return (
<div className='container'></div>
);
}

Try this instead:
export default function ComposeEmailForm({ handleCompose, template_titles }) {
console.log(template_titles);
return (
<div className='container'></div>
);
You can't use this when your component is a function and not a class.
And when passing it, you need to drop the this too:
<ComposeEmailForm
handleCompose={this.sendNewEmail}
template_titles={template_titles}
/>
since you define it as such in your render function.

Actually, in the function component, you don't too use this, especially when you destruct props in the parentheses of the argument, then you can access to you props like below:
export default function ComposeEmailForm({ handleCompose, template_titles }) {
console.log(template_titles, handleCompose);
return (
<div className='container'></div>
);
};

Related

JSX function is not working properly and function part is not getting shown on web page

The code is one of the snippet of one of the react component for a project. I am have imported here css file for the styling and have already done with material ui part. In the main section the function written for The newArticle is not appearing on web page.
import "./Widgets.css";
import InfoIcon from '#mui/icons-material/Info';
import FiberManualRecordIcon from '#mui/icons-material/FiberManualRecord';
function Widgets() {
{/*BEM naming convention*/}
const newsArticle = (heading, subTitle) => {
<div className="widgets__article">
<div className="widgets__articleLeft">
<FiberManualRecordIcon/>
</div>
<div className="widgets__articleRight">
<h2>{heading}</h2>
<p>{subTitle}</p>
</div>
</div>
};
return (
<div className="widgets">
<div className="widgets__header">
<h2>LinkedIn News</h2>
<InfoIcon/>
</div>
{newsArticle("Some text","few text")}
{newsArticle("Some sentences","Some sentences")}
{newsArticle("Some sentences","Some sentences")}
{newsArticle("few text","few text")}
{newsArticle("few text","few text")}
{newsArticle("few text","few text")}
</div>
);
};
export default Widgets;
You need to add a return statement for your JSX. You missed that in your method. Change your code like the below.
const newsArticle = (heading, subTitle) => {
return (
<div className="widgets__article">
<div className="widgets__articleLeft">
<FiberManualRecordIcon />
</div>
<div className="widgets__articleRight">
<h2>{heading}</h2>
<p>{subTitle}</p>
</div>
</div>
);
};
I would suggest you create a component if you want to return JSX. I am attaching the sandbox with components.

How to pass ref to component in React?

I am using a library called react-swipe (not especially relevant), which exposes next() and prev() methods on the instance, which I am accessing through a ref.
When I have the ReactSwipe component in my main App.js file this works perfectly well, e.g.:
_handlePrev() {
this.reactSwipe.prev()
}
_handleNext() {
this.reactSwipe.next()
}
render() {
let singlePlanets
singlePlanets = this.state.planetData.map(data => {
return (
<div className="single-planet" key={data.id}>
<div className="image">
<img src={emptyPlanet} alt={data.name} />
</div>
<h2>{data.name}</h2>
<div className="extract" dangerouslySetInnerHTML={{ __html: data.extract }} />
</div>
)
})
return (
<div className="app-container">
<TitleBar />
<ReactSwipe ref={reactSwipe => this.reactSwipe = reactSwipe} className="content" key={singlePlanets.length}>
{singlePlanets}
</ReactSwipe>
<MenuBar handleNext={this._handleNext.bind(this)} handlePrev={this._handlePrev.bind(this)} />
</div>
)
}
But what I'm trying to do is separate out the ReactSwipe and planetData mapping logic into its own component (code below), however when I do this (by trying to pass the ref through as a prop) I always get the error this.reactSwipe.prev() (or .next()) is not a function, no matter what I try. I'm wondering - what is the correct way to go about this?
This what I have in my return in App.js:
<PlanetInfo planetData={this.state.planetData} swipeRef={reactSwipe => this.reactSwipe = reactSwipe} />
and in PlanetInfo component:
return (
<ReactSwipe ref={this.swipeRef} className="content" key={singlePlanets.length}>
{singlePlanets}
</ReactSwipe>
)
Replace ref={this.swipeRef} with ref={this.props.swipeRef} in PlanetInfo component.

React cannot read property of undefined when accessing from e.g. IF statement

Redux turned my app state to props and I would like to access the properties of certain props once the API request is done. Yet, my page can't render as I get the above message.
kicking off GET reqest:
componentWillMount() {
this.props.renderRoles(this.props.params.roleID);
};
Rendering users does work though:
renderUsers(){
return this.props.roleDetails.userList.map((user)=>{
return(
<li className='list-group-item eventUserList' background-color="#f2f2f2" key={user._id}>
{user.userName}
</li>
);
});
};
render() {
const { handleSubmit, fields: {} } = this.props;
This is the problem part. Somehow, properties of this.props get undefined if I look for their properties:
if (this.props.roleDetails.roleName){
return (
If I only look for this.props.roleDetails, it does work, but not when for its properties:
if (this.props.roleDetails){
return (
<div className='container-fluid'>
<form>
<div className="roleDetails">
<div className="roleName">
{this.props.roleDetails.roleName}
</div>
</div>
<div className="roleUsers">
<div className="userDetails">
<h4 className="listOfUsers">Role Owner :</h4>
<ul>
{this.renderUsers()}
</ul>
</div>
</div>
<div>
<div className="submitRole" onClick={this.submitForRole.bind(this)}>Apply</div>
</div>
</form>
</div>
);
}else {
return (
<div>
</div>
);
}
}
}
function mapStateToProps(state) {
return{
roleDetails: state.api.roleDetails,
refreshedRole: state.api.refreshedRole
}
}
export default reduxForm({
form: 'roleView',
fields: []
}, mapStateToProps, actions)(roleView);
Other similar questions are related to functions, but in my case is about accessing props therefore .bind(this) doesn't work.
if (this.props.roleDetails.roleName) looks like roleDetails undefined befor You get data with request, so if You will try to get access to it's property roleName you will get an error.
if (this.props.roleDetails && this.props.roleDetails.roleName) shouldn't throw errors.
And it's not good idea to fetch data in componentWillMount, use componentDidMount instead.

add a custom save function to react modal footer button to both handle custom save action and trigger a close

I am getting all mixed up at how I might attach a custom function to a prop I passed into a modal called handleSaveAction as you can see below. I want to allow whoever calls the component to be able to pass in a custom save function depending on what needs to be saved. On click of the 'Save Button' I want to call the handleSaveAction that is being passed in as well as triggering the modal to close right after, using closeModal. How can I do this in a simple way?
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
const UiModal = React.createClass({
getInitialState(){
return { isOpen: false };
},
openModal() {
this.setState({ isOpen: true });
},
closeModal() {
this.setState({ isOpen: false });
},
render() {
const { openBtnText, header, subHeader, body, footer, footerText, actionBtnText='See More', closeBtnText='Cancel', placement='central-small', handleSaveAction } = this.props;
return (
<div>
<div className="button" onClick={this.openModal}>{ this.props.openBtnText }</div>
<div>
<ReactCSSTransitionGroup transitionName="modal-anim" transitionLeaveTimeout={500} transitionEnterTimeout={500} transitionAppear={true}
transitionAppearTimeout={500}>
{ this.state.isOpen ?
<div className={`ui-modal-${placement}`} key={placement}>
<div className="ui-modal-header">
<UiHeader
textTitle={'UiModal Header'}
rightSideContent={<UiIcon icon='cancel' dimensions={[18, 18]} color='header-gray' onClick={this.closeModal} />}
/>
</div>
<div className="ui-modal-body">
{body}
</div>
<div className="ui-modal-footer">
<div className="ui-modal-footer-button-group">
<div className="ui-modal-footer-button-close" onClick={this.closeModal}>{closeBtnText}</div>
<div className="ui-modal-footer-button button" onClick={this.handleSave}>{actionBtnText}</div>
</div>
<div className="ui-modal-footer-text">{footerText}</div>
</div>
</div>
: null }
</ReactCSSTransitionGroup>
</div>
</div>
);
}
});
export default UiModal;
You can add a handleSave function to your class that gets called before the function passed in. In that function, check if a function was passed and call that before called this.closeModal(). Something like:
handleSave() {
if (this.props.handleSaveAction) {
this.props.handleSaveAction
}
this.closeModal();
}
Then on the button: onClick={this.handleSave.bind(this)}.
Also, worth nothing, both React.createClass() and react-addons-css-transition-group are deprecated, it might be worth updating your version of React and using ES6 classes.

Any use of a keyed object should be wrapped in React.addons.createFragment(object)

let playerInfo = [{
name: 'jose',
country: 'USA',
age: 47
}];
export default class PlayersInfo extends React.Component {
static getProps() {
return {};
}
render() {
let playerInf = playerInfo.map((playerData, index) => {
return <div className="item" key={index}>{playerData}</div>
});
return <div>
<div>
{playerInf}
</div>
<RouteHandler />
</div>;
}
Why am I getting this error in the browser's console?
Warning: Any use of a keyed object should be wrapped in React.addons.createFragment(object) before being passed as a child.
I put together a JSBin for you. Basically, the warning comes from this line:
return <div className="item" key={index}>{playerData}</div>
It's because playerData is an object and ReactJS doesn't know how to render it.
If you change that to the following, it won't give you the warning:
return (
<div className="item" key={index}>
<div>Name: {playerData.name}</div>
<div>Country: {playerData.country}</div>
<div>Age: {playerData.age}</div>
</div>
);
Why am I getting this error in the browser's console?
Because you are passing an object (playerData) as child to a React Component.
I tend to run into this when rendering a Date object by mistake. You need to stringify these manually:
Produces warning:
<div>{ new Date() }</div>
Works ok:
<div>{ String(new Date()) }</div>
Does this work?
return <div>
<div>
{playerInf}
</div>
<div>
<RouteHandler />
</div>;
</div>
}

Categories

Resources