Accessing Props Error in Stateful Child Component - reactjs

I am trying to access the parent object within the stateful child component, but I can't seem to understand why the object is not found. This component was converted from stateless and worked fine, so I'm curious what broke post-conversion. Do I need to set an empty array within the state and then a function to setState with the prop?
Here is the error:
Uncaught ReferenceError: props is not defined
At line this.props.blogs.map((blog, index) => {
Here are the two components:
//GET /api/app and set to state
class BlogFeedContainer extends React.Component{
constructor(props, context) {
super(props, context);
this.state = this.context.data || window.__INITIAL_STATE__ || {blogs: []};
}
fetchList() {
fetch('http://localhost:3000/api/test')
.then(res => {
return res.json();
})
.then(data => {
console.log(data);
this.setState({ blogs: data.blog, user: data.user, csrf: data.csrfToken });
})
.catch(err => {
console.log(err);
});
}
componentDidMount() {
this.fetchList();
}
render() {
return (
<div className="container">
<h2>Comments List</h2>
<BlogFeed {...this.state} />
</div>
)
}
};
//Loop through JSON and create Blog and Comment Container Component
class BlogFeed extends React.Component {
constructor(props){
super(props);
this.state = {
comments: []
};
}
render(){
return (
<div>
{
this.props.blogs.map((blog, index) => {
return (
<div className="row">
<div className="col-md-6 col-md-offset-3 blog-card">
<BlogCard {...blog} key={blog.blogIdHash} user={props.user} />
<Comments {...blog} key={index} blogId={blog.blogIdHash} csrf={props.csrf}/>
</div>
</div>
);
})
}
</div>
);
}
}

You spotted the error in the wrong line.
The this keyword is missing in user and csrf props:
<BlogCard {...blog} key={blog.blogIdHash} user={this.props.user} />
<Comments {...blog} key={index} blogId={blog.blogIdHash} csrf={this.props.csrf} />

Related

How to change state of a sibiling, if I click on a component?

I have three components that render a list of available timeslots.
If I click on a timeslot on the list of component1, it gets selected, now, If a sibiling component, let's call it component2, also has a timeslot that matches the one that had been clicked on component1, I want the one in component2 to be greyed out.
How can I do this?
The components that render the lists of available timeslots are called CompanyPanel:
export default class CompanyPanel extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedTime: 'None',
times: this.props.times,
}
this.chooseTime = this.chooseTime.bind(this)
this.deleteTime = this.deleteTime.bind(this)
}
componentDidMount () {
this.chooseTime(this.state.selectedTime)
}
deleteTime (time) {
this.setState( ({times}) => ({
times: [...this.state.times].filter( t => t !== time),
}))
}
chooseTime (selectedTime) {
this.setState({
selectedTime,
})
}
render() {
const { selectedTime, times } = this.state
return (
<React.Fragment>
<div className="flex-auto pa3">
<div className="ba mv2">
<p className="tc pa2 dib bg-near-white">{this.props.name}</p>
</div>
<div className="ba mv2">
<p className="tc pa2 dib bg-red white">{selectedTime}</p>
</div>
<div className="ba mv2">
{times.map((time, i) => (
<div key={i} className="bg-green">
<span className="pa2 red pointer ma2 bg-white" onClick={() => this.deleteTime(time)}>X</span>
<p onClick={() => this.chooseTime(time.dateUTCString)} className="tc pa2 dib bg-yellow">{time.dateUTCString}</p>
</div>
))}
</div>
</div>
</React.Fragment>
)
}
}
And those CompanyPanel components are being wrapper by a parent component called CompaniesDashboard:
export default class CompaniesDashboard extends React.Component {
constructor(props) {
super(props)
this.state = {
error: null,
data,
}
this.isLoading = this.isLoading.bind(this)
}
isLoading() {
return this.state.posts === null && this.state.error === null
}
render() {
const { data, error } = this.state
return (
<React.Fragment>
{this.isLoading() && <p>LOADING</p>}
{error && <p>{error}</p>}
<div className="flex">
{data && data.map((company, i) => (
<CompanyPanel key={i} times={company.times} name={company.name} />
))}
</div>
</React.Fragment>
)
}
}
I think i need to somehow to set a state in the parent, when the chooseTime method is clicked inside if the CompanyPanel component. But not sure how to do it.

Cannot read property 'tabsDivIframe' of undefined - React

I am creating an application with tabs and divs to show the iframes or divs associated with the tabs. I have a navigation menu that works perfectly, when you click on one of the menu items you create a new tab and at the same time you should create a div / iframe (as applicable). The creation of the div is failing in my DivAndIframe class, it gives this error Can not read property 'tabsDivIframe' of undefined when I try to paint <DivAndIframe tabsDivIframe {this.props.divIframe.tabsDivIframe} />. It does not make sense because in my class App is an array with content that does not throw any errors.
class App extends Component {
constructor(props, context){
super(props, context);
["openTabs"].forEach((method) => {
this[method] = this[method].bind(this);
});
this.state = {
tabs:{
tabsLi: [],
},
divIframe:{
tabsDivIframe: [],
},
showtabs: true,
}
}
openTabs(e, url, iframe, trdtitle){
e.preventDefault();
//Change the state
this.setState({
showtabs: false,
})
//Creating tabs + iframe/div
if (this.state.tabs.tabsLi.includes(trdtitle) === false){
this.setState({
tabs: { tabsLi:[...new Set(this.state.tabs.tabsLi),trdtitle].filter(function(el) { return el; })},
divIframe: { tabsDivIframe:[...new Set(this.state.divIframe.tabsDivIframe),url].filter(function(el) { return el; })},
}, () => {
//this.state.divIframe.tabsDivIframe is an array
console.log(this.state.tabs.tabsLi);console.log(this.state.divIframe.tabsDivIframe)
})
}
}
render(){
return (
<>
<section className='section'>
<Tabs
navigation={this.state.navigation}
textvalue={this.state.textvalue}
showtabs={this.state.showtabs}
tabs={this.state.tabs}
tabsLi={this.state.tabs.tabsLi}
tabsDivIframe={this.state.divIframe.tabsDivIframe}
openTabs={this.openTabs}
removeTab={this.removeTab}
/>
</section>
</>
)
}
}
class Tabs extends Component {
render(){
return(
<div id="content-tabs" className="tabs">
{( this.props.showtabs)
? (
<>
<div className="waiting-leads">
<p>Parece que todavía no hay ningún lead...</p>
<h3>¡Ánimo, ya llega!</h3>
<img src={imgDinosaurio} alt="Dinosaurio"></img>
</div>
</>
) : (
<>
<ul id="resizable" className="content" >
<LiTabs
tabsLi={this.props.tabs.tabsLi}
removeTab={this.props.removeTab}
/>
</ul>
<DivAndIframe
tabsDivIframe={this.props.divIframe.tabsDivIframe}
/>
</>
)}
</div>
);
}
}
class LiTabs extends Component{
render(){
return(
<>
{this.props.tabsLi.map((value, index) =>
<li key={index}>
<span>{value}</span>
</li>
)}
</>
);
}
}
class DivAndIframe extends Component{
render(){
return(
<>
{this.props.tabsDivIframe.map((url, index) =>
<div key={index}>
<span>Test {url}</span>
</div>
)}
</>
);
}
}
I do not understand why DivAndIframe does not work when it is exactly the same as LiTabs
I think you have a typo.
When rendering Tabs, in App, you pass the props:
<Tabs
navigation={this.state.navigation}
textvalue={this.state.textvalue}
showtabs={this.state.showtabs}
tabs={this.state.tabs}
tabsLi={this.state.tabs.tabsLi}
tabsDivIframe={this.state.divIframe.tabsDivIframe}
openTabs={this.openTabs}
removeTab={this.removeTab}
/>
And inside Tabs you have:
<DivAndIframe
tabsDivIframe={this.props.divIframe.tabsDivIframe}
/>
You aren't passing divIframe to Tabs and that is why you are getting Can not read property 'tabsDivIframe' of undefined. this.props.divIframe is undefined.
Maybe it should be other name?
Like this.props.tabsDivIframe ?

React - Map content inside a div

Good Morning! Why does my map content stay outside the "blog--div" div?
It's getting loose on Body and I do not know why. Help-me, please!
I try to put a border around the contents of the "blog--div" but the content becomes loose, making it impossible to apply styles.
imports[...]
class Blog extends Component {
constructor(props) {
super(props)
this.state = {
post: [],
}
}
componentDidMount() {
this.setState({ isLoading: true })
fetch(`${API}`)
.then(res => res.json())
.then(res => {
this.setState({
post: [res],
isLoading: false,
})
})
}
render() {
const { isLoading } = this.state
if (isLoading) {
return <Loading />
}
return (
<div className="blog">
<p className="blog__title">Blog</p>
{this.renderBlog()}
</div>
)
}
renderBlog() {
const page = this.state.post.map((post, key) => {
return (
<div className="blog--div" key={key}>
<div className="blog__post">
<div className="blog__post--title">
<p><a target="_blank" rel="noopener noreferrer" href={post[0].link}>{post[0].title.rendered.replace('Visit.Rio', 'Projeto 1')}</a></p>
</div>
<div className="blog__post--description">
<p>{post[0].excerpt.rendered.replace('Visit.Rio', 'Projeto 1')}</p>
</div>
</div>
</div>
)
})
return page
}
}
export default Blog

Updating State Breaks Child Prop Component

I am still trying to get a handle on parent-child data sharing and have an issue where my stateful component has an array of objects that display correctly within my child prop components via componentWillReceiveProps(), but when I trigger my updateCommentsFunc() function, which is triggered by a child component form, the POST is called and value is appended to the array, but I get an undefined error from my child component that demonstrates that the data isn't flowing post state update.
Am I using the wrong method? Should I add something to my updateCommentsFunc()?
Here is the console error:
Uncaught TypeError: Cannot read property 'picture' of undefined
at Comment (comment.js?2fa6:15)
at mountIndeterminateComponent (react-dom.development.js?cada:10400)
at beginWork (react-dom.development.js?cada:10601)
at performUnitOfWork (react-dom.development.js?cada:12573)
at workLoop (react-dom.development.js?cada:12682)
at HTMLUnknownElement.callCallback (react-dom.development.js?cada:1299)
at Object.invokeGuardedCallbackDev (react-dom.development.js?cada:1338)
at invokeGuardedCallback (react-dom.development.js?cada:1195)
at performWork (react-dom.development.js?cada:12800)
at scheduleUpdateImpl (react-dom.development.js?cada:13185)
Triggered at line:
<img src={props.user.picture} className="comment__record-profile"/>
This is the parent component which is fed an object that has its nested array mapped and stored in an array in the state:
//Loop through JSON and create Comment and Comment Container Component
class CommentFeed extends React.Component {
constructor(props){
super(props);
this.state = {
comments: []
};
this.updateCommentsFunc = this.updateCommentsFunc.bind(this);
}
//Load Array to component
componentWillReceiveProps(nextProps){
let commentArr = [];
nextProps.comments.map((comment) => {
comment.comment_comments.map((comment) => {
commentArr.push(comment);
})
})
this.setState({comments: commentArr});
}
//Append new POST value to commentArr
updateCommentsFunc(newComments){
var updatedCommentArr = this.state.comments.slice();
updatedCommentArr.push(newComments)
this.setState({comments: updatedCommentArr});
}
render(){
return (
<div>
{
this.props.comments.map((comment, index) => {
return (
<div className="row">
<div className="col-md-6 col-md-offset-3 comment-card">
<CommentCard {...comment} key={comment.commentIdHash} user={this.props.user} />
<Comments comments={this.state.comments} key={index} commentId={comment.commentIdHash} csrf={this.props.csrf} updateComments={this.updateCommentsFunc}/>
</div>
</div>
);
})
}
</div>
);
}
}
Here is the child component split into a form and displayed comments:
//Blog Comment - Container
export default class Comments extends React.Component {
render() {
return (
<div className="blog-comment-container">
<CommentForm updateComments={this.props.updateComments} blogId={this.props.blogId} csrf={this.props.csrf}/>
{ this.props.comments.map((comment, i) =>
<AttachedComment commentObj={comment} blogComponentId={this.props.blogId}/>
)}
</div>
);
}
}
Here is the form calling this.props.updateComments() with the returned JSON data from the POST:
class CommentForm extends React.Component {
constructor(props){
super(props);
this.state = {
value: ''
};
this.postComment = this.postComment.bind(this);
this.onChange = this.onChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
postComment(comment, blogId, csrfToken) {
var body = { comment: comment };
var route = 'http://localhost:3000/app/blog/' + blogId + '/comment';
fetch(route,
{
method: 'POST',
body: JSON.stringify(body),
headers: {
'X-CSRF-Token': csrfToken,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => {
return res.json();
})
.then(data => {
this.props.updateComments(data)
})
.catch(err => {
console.log(err);
});
}
onChange(e){
this.setState({
value: e.target.value
});
}
handleSubmit(e){
e.preventDefault();
this.postComment(this.state.value, this.props.blogId, this.props.csrf);
}
render(){
return (
<div className="blog-comment__form">
<div className="row">
<div className="col-md-12">
<label>Comment:</label>
</div>
</div>
<div className="row">
<form action={"/app/blog/" + this.props.blogId + "/comment"} method="post" onSubmit={this.handleSubmit}>
<input type="hidden" name="_csrf" value={this.props.csrf}/>
<div className="col-md-9">
<textarea name="comment" className="blog-comment__form-text-area" onChange={e => this.setState({ value: e.target.value })} value={this.state.value}></textarea>
</div>
<div className="col-md-3">
<button type="submit" className="blog-comment__form-button" disabled={!this.state.value}>Comment</button>
</div>
</form>
</div>
</div>
)
}
}
Here is the conditional that checks to see if the nested array Id matches the id from the fed object at the parent:
const AttachedComment = props => {
if(props.commentObj.blogIdHash == props.blogComponentId){
return (
<Comment {...props.commentObj} key={props.commentObj.blogCommentId}/>
)
} else {
return null;
}
}
Finally, if that returns TRUE then the component where the error appeared is rendered:
const Comment = props => {
return (
<div className="comment-comment__record">
<div className="row">
<div className="col-md-12">
<div className="comment-comment__meta">
<div className="row">
<div className="col-md-6">
<img src={props.user.picture} className="comment-comment__record-profile"/>
</div>
<div className="col-md-6">
</div>
</div>
</div>
<h5>{props.user_id}</h5>
<h4>{props.comment}</h4>
<h3>{props.synotate_user.fullNameSlug}</h3>
</div>
</div>
</div>
)
}

Highlight item onClick - React.js

Add underscore to category-item onClick and remove underscore for any other item. Found some answers on how to do this with only two components, a "item-container-component" and "item-components". But i have three components involved. This is what I hope to achieve:
Archive-component (mother component):
class Archive extends React.Component {
constructor(props){
super(props);
this.state = {
products: [],
category: "",
activeIndex: 0
}
this.filterHandler = this.filterHandler.bind(this);
}
filterHandler(tag, index){
console.log('INDEX: ' + index);
this.setState({
category: tag,
activeIndex: index
})
}
componentDidMount(){
const myInit = {
method: "GET",
headers: {
"Content-Type": "application/json"
}
};
fetch("/getProducts", myInit)
.then((res) => {
return res.json();
})
.then((data) => {
this.setState({products:data});
})
.catch(function(err) {
console.log('ERROR!!! ' + err.message);
});
}
render() {
return (
<div>
<Menu />
<div className="archive-container">
<div className="archive-wrapper">
<CategoryContainer
filterHandler={this.filterHandler}
products={this.state.products}
activeIndex={this.state.activeIndex}
/>
<br/><br/>
<ProductContainer
products={this.state.category.length
? this.state.products.filter((prod) => prod.category === this.state.category)
: this.state.products.filter((prod) => prod.category === 'Paint')
}
/>
</div>
</div>
<Footer />
</div>
);
};
};
Category-container component:
class CategoryContainer extends Component {
render(){
const categories = [...new Set(this.props.products.map(cat => cat.category))];
return (
<div>
<ul className="filterList">{
categories.map((cat, index) =>
<CategoryItem
key={index}
index={index}
category={cat}
active={index === this.props.activeIndex}
handleClick={() => this.props.filterHandler(cat, index)}
/>
)
}</ul>
</div>
);
};
};
Category-item component:
class CategoryItem extends Component {
render(){
return (
<div>
<li
className={this.props.active ? 'active' : 'category'}
onClick={this.props.handleClick}
>
{this.props.category}
</li>
</div>
);
};
};
Yelp!
M
Suppose you have a li tag for which you want to change the color of.
you could probably try something like this.
<li id="colorChangeOnClick" class="redColor" onclick={this.onClickFunction()}></li>
Then in your react class you can have the on click function with parameters e:
onClick(e) {
//This would give you all the field of the target
console.log(e.target.elements);
// you can do all sorts of Css change by this way
e.target.element.class="newGreenColor";
}
Also make sure to make a state or a prop change otherwise the page would not render again.

Resources