How to call twofunction in componentDidMount? - reactjs

I failed to call two funtion in componentDidMount.When I clicked bangla its change and when i clicke english its change but during routing it stays only english so i wanted to set the state in componentDidMount,but it only invoke one funtion.if click the bangla it set bangla but when i change the routing its remain the same lang. so how can i set it.
import React, { Component } from 'react';
import { connect } from "react-redux";
import {setLanguage} from "../../actions";
import { Link } from "react-router-dom";
class MenuComp extends Component {
constructor(props){
super(props);
this.setLang = this.setLang.bind(this);
this.state= {
"maintitle": {
"titlelist": [
{"title1":"Timetable"},
{"title2":"Ticket Prices"},
{"title3":"About Us"}
]
}
};
}
setLang(lang){
this.props.setLanguage(lang);
this.props.history.push('/menu');
}
changeLanguage = () => {
this.setState({
"maintitle": {
"titlelist": [
{"title1":"সময়সূচী"},
{"title2":"টিকেটর মূল্য"},
{"title3":"আমাদের সম্পর্কে"}
]
}
});
};
changeLang = () => {
this.setState({
"maintitle": {
"titlelist": [
{"title1":"Timetable"},
{"title2":"Ticket Prices"},
{"title3":"About Us"}
]
}
});
};
componentDidMount() {
this.changeLanguage();
this.changeLang();
}
render() {
return (
<div className="Menu">
<div className="menu-header">
<div className="container-fluid p-0">
<div className="row m-0">
<div className="col-md-4 p-0 d-flex justify-content-end">
<div className="align-self-center">
<a className="lang" onClick={() => { this.setLang('bn'); this.changeLanguage(); }}>Bangla</a> |
<a className="lang l-active" onClick={() => { this.setLang('en'); this.changeLang(); }}>English</a>
</div>
</div>
</div>
</div>
</div>
<main className="navigation">
<div className="container-fluid p-0">
<div className="row m-0">
<div className="col-md-4 pl-0">
<Link to="/timetable" className="lang">
<div className="card-content">
<h6 className="card-title">{
this.state.maintitle.titlelist.map((title, i)=>{
return (<p key={i}>{title.title1} </p>)
})
}</h6>
</div>
</Link>
</div>
<div className="col-md-4 pl-0">
<Link to="/ticketprice" className="lang">
<div className="card-content">
<h6 className="card-title">{
this.state.maintitle.titlelist.map((title, i)=>{
return (<p key={i}>{title.title2} </p>)
})
}</h6>
</div>
</Link>
</div>
</Link>
</div>
</div>
</div>
</main>
</div>
);
}
}
function mapStateToProps(state){
return {
lang: state.lang.lang
}
}
const Menu = connect(mapStateToProps, {setLanguage})(withRouter(MenuComp));
export default Menu;

It's an asynchronous problem. So, the setState method runs asynchronously. This makes reading this.state right after calling setState() a potential pitfall.
So, the lines inside your componentDidMount method get executed, however, you can't predict which one of them will finish before the other.
Now, I don't completely understand what you're trying to achieve, but instead, use componentDidUpdate or a setState callback (setState(updater, callback)): something like this:
this.setState((state, props)=> ({
"maintitle": {
"titlelist": [
{"title1":"সময়সূচী"},
{"title2":"টিকেটর মূল্য"},
{"title3":"আমাদের সম্পর্কে"}
]
}
}), ()=> {// do what you want next!})
// (this could be inside your componentDidMount!
If that didn't help, please let me know!

Related

Loop through array in React and create elements (not list items) from it

I'm learning React and have done a fair bit of research on this. I've quickly discovered that the map() function is what I think I should be using for looping through an array.
But, my problem is all the examples in the React documentation and in the SO questions I've viewed use <ul> and <li> HTML elements to handle the output.
I'm not sure that my use case is "correct" as far as React structure is concerned, but, I want to output a <div> with some child elements each time I loop through.
Here is my static code so far:
const Comment = () => {
return (
<div className="commenter">
<div className="commenter-inner">
<div className="commenter-left">
<img src={chachi}/>
<p className="commenter-name">Scott Baio</p>
</div>
<div className="commenter-comment">
<p>Ehhhh!! Joanie loves Chachi!!!</p>
</div>
</div>
</div>
)
}
This works, but now if I have additional comments I want to be able to serve up the same block of code again but with the new commenters name, image, comment content etc.
So I've now made an array to house my multiple commenters, and things aren't really working anymore.
import React, { Component } from 'react'
import fonzie from "./img/the-fonz.jpg";
import chachi from "./img/chachi.jpg";
const Comments = [
{
id: 1,
name: 'Hello World',
photo: fonzie,
comment: 'Welcome to learning React!'
},
{
id: 2,
name: 'Hello World',
photo: chachi,
comment: 'Welcome to learning React!'
}
];
const commentEngine = props.Comments.map((comment) =>
<div className="commenter" key={comment.id}>
<div className="commenter-inner">
<div className="commenter-left">
<img src={comment.photo}/>
<p className="commenter-name">{comment.name}</p>
</div>
<div className="commenter-comment">
<p>{comment.comment}</p>
</div>
</div>
</div>
);
class Comments extends Component {
render() {
return (
<div className="comments-section col-md-10 offset-md-1 col-sm-12">
<h4>Comments</h4>
<commentEngine />
</div>
);
}
}
export default Comments
At this point I'm unsure how to verify if my loop is working in the first place and how to get the output properly displaying in my app.
Any help is greatly appreciated, as is insight into whether or not this is well structured or should be separate components.
Thanks!
It sounds like you want to re-use the Comment component with data passed by Comments. In React, this is done via props.
So, you'll want to pass the images's src, the name, and the description:
const comments = [
{
id: 1,
name: "Hello World",
photo: fonzie,
comment: "Welcome to learning React!",
},
{
id: 2,
name: "Hello World",
photo: chachi,
comment: "Welcome to learning React!",
},
];
class Comments extends Component {
render() {
return (
<div className="comments-section col-md-10 offset-md-1 col-sm-12">
<h4>Comments</h4>
{comments.map((comment) => {
return (
<Comment
key={comment.id} // https://reactjs.org/docs/lists-and-keys.html
name={comment.name}
imgSrc={comment.photo}
comment={comment.comment}
/>
);
})}
</div>
);
}
}
Notice that I've renamed the constant array Comments to comments so that the name doesn't clash with the Comments component.
Then in the Comment component, you can access these props via the argument passed to the function component:
const Comment = (props) => {
return (
<div className="commenter">
<div className="commenter-inner">
<div className="commenter-left">
<img src={props.imgSrc} />
<p className="commenter-name">{props.name}</p>
</div>
<div className="commenter-comment">
<p>{props.comment}</p>
</div>
</div>
</div>
);
};
Additionally, we can make the code a bit less verbose by leveraging object destructuring:
class Comments extends Component {
render() {
return (
<div className="comments-section col-md-10 offset-md-1 col-sm-12">
<h4>Comments</h4>
{comments.map(({ id, name, photo, comment }) => {
return (
<Comment key={id} name={name} imgSrc={photo} comment={comment} />
);
})}
</div>
);
}
}
// ...
const Comment = ({ imgSrc, name, comment }) => {
return (
<div className="commenter">
<div className="commenter-inner">
<div className="commenter-left">
<img src={imgSrc} />
<p className="commenter-name">{name}</p>
</div>
<div className="commenter-comment">
<p>{comment}</p>
</div>
</div>
</div>
);
};
const commentEngine = (comments) => {
return comments.map((comment)=>{
return (
<div className="commenter" key={comment.id}>
<div className="commenter-inner">
<div className="commenter-left">
<img src={comment.photo}/>
<p className="commenter-name">{comment.name}</p>
</div>
<div className="commenter-comment">
<p>{comment.comment}</p>
</div>
</div>
</div>
)})
class Comments extends Component {
render() {
return (
<div className="comments-section col-md-10 offset-md-1 col-sm-12">
<h4>Comments</h4>
{commentEngine(props.Comment)}
</div>
);
}
}
Now when you render Comments you need to pass the Comment props.
<Comments Comment={Comments}/>
USAGECASE
import React, { Component } from 'react'
import fonzie from "./img/the-fonz.jpg";
import chachi from "./img/chachi.jpg";
const Comments = [
{
id: 1,
name: 'Hello World',
photo: fonzie,
comment: 'Welcome to learning React!'
},
{
id: 2,
name: 'Hello World',
photo: chachi,
comment: 'Welcome to learning React!'
}
];
const Comment = props =>
const {comment} = props;
<div className="commenter" key={comment.id}>
<div className="commenter-inner">
<div className="commenter-left">
<img src={comment.photo}/>
<p className="commenter-name">{comment.name}</p>
</div>
<div className="commenter-comment">
<p>{comment.comment}</p>
</div>
</div>
</div>
);
class Comments extends Component {
render() {
return (
<div className="comments-section col-md-10 offset-md-1 col-sm-12">
<h4>Comments</h4>
{Comments.map((comment,index) => <Comment key={'[CUSTOM_KEY]'} props={comment}> )}
</div>
);
}
}
export default Comments
ANSWER
First of all, You can use index parameter in Array.map
Secondly, if you want to use list component you can make Single Component like <Comment comment={comment}> and you can use it with Array.map
And It is very good to study How to make functional component

React Error: Cannot read property 'map' of undefined

I have been trying to resolve this error for almost 2 hours but no luck. I have even researched and used the bind method but still no luck with mapping a props that was passed through a parent component. Your help will be greatly appreciated.
import React from "react";
import { Link } from "react-router-dom";
const PostList = ({ postItem }) => {
postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
<Link to="/create">
<ion-icon
style={{ color: "#fc5185", fontSize: "20px" }}
name="trash-outline"
></ion-icon>
</Link>
</div>
</div>
));
};
export default PostList;
And the parent component is
class Dashboard extends Component {
state = {
posts: [
{
id: 1,
title: "Hello",
comment: "it is sunny today",
},
],
};
createPost = (title, comment) => {
const newPost = {
id: Math.floor(Math.random() * 1000),
title,
comment,
};
this.setState({
posts: [...this.state.posts, newPost],
});
};
render() {
return (
<div>
<CreatePost createPost={this.createPost} />
<PostList postItem={this.state.posts} />
</div>
);
}
}
export default Dashboard;
I guess you have missed to add return to the PostList component, you can do it in three ways (read about arrow functions)
const PostList = ({ postItem }) => postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
</div>
</div>
));
const PostList = ({ postItem }) => (
postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
</div>
</div>
));
);
const PostList = ({ postItem }) => {
return postItem.map((post) => (
<div className="mx-auto mb-3 card w-75" key={post.id}>
<div className="card-body">
<h5 className="card-title">{post.title}</h5>
<p className="card-text">{post.comment}</p>
</div>
</div>
));
}
Here is the working example

react redux two components

I have a component that will display the products which is coming from backend and a component that receives the products to filter but I have doubt that receive by redux my product list.
should i put for my filters component receive?
or should return the same as I get in my product component?
or should I create an action to filter what I need already?
my home:
return (
<div className="container">
<h1>Shopping</h1>
<hr />
<div className="row">
<div className="col-md-3"><Filters/></div>
<div className="col-md-9"><Products/></div>
</div>
</div>
)
my component products:
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { ProductsFetchData } from '../../store/actions/productsFetch';
import util from '../../util';
class HomeProducts extends Component {
componentDidMount() {
this.props.fetchData('/products');
}
render() {
const productItems = this.props.products.map( product => (
<div className="col-md-4 pt-4 pl-2">
<div className = "thumbnail text-center">
<a href={`#${product.id}`} onClick={(e)=>this.props.handleAddToCard(e,product)}>
<p>
{product.name}
</p>
</a>
</div>
<b>{util.formatCurrency(product.price)}</b>
<button className="btn btn-primary" onClick={(e)=>this.props.handleAddToCard(e,product)}>Add to Cart</button>
</div>
)
)
return (
<div className="container">
<div className="row">
{productItems}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
products: state.Products,
hasErrored: state.ProductsHasErrored,
isLoading: state.ProductsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: () => dispatch(ProductsFetchData())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(HomeProducts);
my components filter
import React, { Component } from 'react';
import './style.css'
class FilterHome extends Component {
render() {
return (
<>
<div className="row">
<button className="filterbt btn btn-danger btn-rounded">Filters</button>
<div className=" mt-4 d-flex flex-column">
<p className="textCategory">CATEGORY</p>
<div className="category d-flex flex-column">
<p>Stat Trak</p>
<p>Normal</p>
</div>
<p className="textCategory">EXTERIOR</p>
<div className="category d-flex flex-column">
<p>Factory New ()</p>
<p>Minimal Wear ()</p>
<p>Field Tested ()</p>
<p>Well Worn ()</p>
<p>Battle Scarred ()</p>
</div>
</div>
</div>
</>
)
}
}
export default FilterHome;
1.redux-state: this is the registering point for all your api responses(all the data from back-end is stored here as prestine and is available as props to any container when you mapStateToProps).
2.local-state: this lives only in your container and all it's child components.
3.filter:
a)from server:
you make a request to the server and get a response of filtered products. this
is more practical.
eg: you have /products?page=1 and you want to search it by some category, let's
say by a specific company. with the data you have at the moment(page 1), you
may have only let's say 1 or even no product relevant to that company, but in fact there are n-numbers of products of the same company available at the server. so this can only be assumed as the
most practical way.
b)filtering from the local-state:
if this is what your'e trying to achieve,
1. you need only one container, HomeProducts
2. make ProductItems as a component. wer'e gonna reuse this component to render both.
**you wrote your filter as an independent container. but those filter functionality should be availabe inside the home page itself. isn't it, i mean you're filtering from the home page itself not from another page. if so, add it to the home page itself
1.HomePage
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { ProductsFetchData } from '../../store/actions/productsFetch';
import util from '../../util';
import ProductItems from '<<..your relative path>>'
import FilterHome from '<<..your relative path>>'
class HomeProducts extends Component {
constructor(props) {
super(props)
this.state = {
productList: null,
}
}
componentDidMount() {
//this.props.fetchData('/products');
this.props.fetchData('page=1');
}
componentWillReceiveProps(nextProps) {
const { productList } = this.state
const { products } = this.props
// this only handles when local state is empty. add your logic here..
!productList && this.setState(prevState => ({
...prevState,
productList: products,
}))
}
handleFilter = (category) => {
// if it's an api call
const { fetchData } = this.props
fetchData(`page=1&category=${category}`)
//or you simply want to filter this local state(not-recommended)
const { products } = this.props
const productsList = [...products].filter(item => item.category === category)
this.setState(prevState => ({
...prevState,
productsList,
}))
}
render() {
const { productList } = this.state
const { handleFilter } = this
return (
<div className="container">
<FilterHome {...{ handleFilter }} />
<ProductItems {...{ productsList }} />
</div>
)
}
}
const mapStateToProps = (state) => {
return {
products: state.Products,
hasErrored: state.ProductsHasErrored,
isLoading: state.ProductsIsLoading
};
};
//it may not suit depends on your api, but you get the idea..
const mapDispatchToProps = (dispatch) => {
return {
// fetchData: () => dispatch(ProductsFetchData())
fetchData: params => dispatch(ProductsFetchData(`/products?${params}`))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(HomeProducts);
2.ProductItems
import React from 'react'
const ProductItem = ({ product }) => {
return (
<div className="col-md-4 pt-4 pl-2">
<div className = "thumbnail text-center">
<a href={`#${product.id}`} onClick={(e)=>this.props.handleAddToCard(e,product)}>
<p>
{product.name}
</p>
</a>
</div>
<b>{util.formatCurrency(product.price)}</b>
<button className="btn btn-primary" onClick={(e)=>this.props.handleAddToCard(e,product)}>Add to Cart</button>
</div>
)
}
const ProductItems = ({ productList }) => {
return (
<div className="row">
{productList && productList.map(product => <ProductItem key={product.id} {...{ product }} />)}
</div>
)
}
export default ProductItems
3.FilterHome
import React from 'react'
const FilterHome = ({ handleFilter }) => {
return (
<div className="row">
<button className="filterbt btn btn-danger btn-rounded">Filters</button>
<div className=" mt-4 d-flex flex-column">
<p className="textCategory">CATEGORY</p>
<div className="category d-flex flex-column">
<a href="" className="text-decoration-none" onClick={() => handleFilter('stat_trak')}><p>Stat Trak</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('normal')}><p>Normal</p></a>
</div>
<p className="textCategory">EXTERIOR</p>
<div className="category d-flex flex-column">
<a href="" className="text-decoration-none" onClick={() => handleFilter('factory_new')}><p>Factory New ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('minimal_wear')}><p>Minimal Wear ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('field_tested')}><p>Field Tested ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('well_worn')}><p>Well Worn ()</p></a>
<a href="" className="text-decoration-none" onClick={() => handleFilter('battle_scarred')}><p>Battle Scarred ()</p></a>
</div>
</div>
</div>
)
}
export default FilterHome
i roughly re-wrote it, may contain bugs..
first add it to the local state and employ a call back to the filter component..
handleFilter = (category) => {
const { Products } = this.state
const products = {...Products}
//or depends on the type, so it wont mutate the real data>> const products = [...Products]
return products.filter(item => item.category === category)
}
this is what is understood from your comment. is that it?

Undefined when Filtering an Array in React JS

I am trying to filter an array in React for only certain items (in my case I want all items that have type: "Plant"). I can get the data from an API successfully but filtering its produces this error: Unhandled Rejection (TypeError): undefined is not an object (evaluating 'data.Array.object')
Here is what the data looks like if I console log it:
data
Here is my full code:
import React from "react";
import { API, graphqlOperation } from 'aws-amplify';
import { listTrackerItems } from '../graphql/queries';
class TrackerPlantsPage extends React.Component {
state = {
plant:'',
plants: [],
active: []
};
async componentDidMount() {
const result = await API.graphql(graphqlOperation(listTrackerItems))
let data = result.data.listTrackerItems.items
console.log(data)
let activePlants = data.Array.filter(t=>t.type === 'Plant');
this.setState({active: activePlants, plants: data });
}
render() {
const { plants, active } = this.state
console.log(plants)
return (
<>
<div class="container">
{/* Cards */}
<div id="toggle-harvested" class="">
<div class="uk-child-width-1-3 uk-grid-small uk-grid-match uk-grid">
{plants.map(item => (
<div key={item.id} class="uk-margin-top uk-margin-bottom">
<div class="uk-card uk-card-secondary uk-card-body">
<div class="uk-card-badge uk-label">Harvested on {item.harvestDate}</div>
<div class="uk-child-width-expand#s uk-text-center" uk-grid>
<div>
<div>
<h3 class="uk-card-title uk-margin-remove-bottom">{item.name}</h3>
</div>
</div>
</div>
<ul class="uk-list uk-list-striped">
<li>Planted: {item.todaysDate}</li>
<li>Assigned: {item.assignedUser}</li>
<li>{item.description}</li>
</ul>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</>
)
}
}
export default TrackerPlantsPage;
Regards
do data.filter(t => t.type === 'Plant') instead.

Not able to get data in props in react js

Following is my code to retrieve data from firebase and view it in a bootstrap carousel. I can see the values in the console but I'm not able to get it in the props on another component.
class JobOfferSlider extends Component {
componentDidMount = () => {
var ref = fire.database().ref("Employers/Employer1");
ref.orderByKey().on("child_added", (snapshot) => {
this.setState({ slidercontents: snapshot.val()})
console.log(this.state.slidercontents);
console.log(this.state.slidercontents.Title)
});
var empref = fire.database().ref("Employers/");
empref.orderByKey().on("child_added", (snapshot) => {
this.setState({ employers: snapshot.key})
console.log(this.state.employers);
});
}
state ={
slidercontents : [], employers : []
}
and i use the props in the following jsx file
class Slidercontent extends Component {
componentWillUpdate = ()=>{
console.log(this.props.employers);
}
render() {
return (
<div className="col-sm text-center border rounded shadow p-3 m-3">
<div className="row">
<div className="col-md-3">
<div className="profilepic"></div>
</div>
<div className="col-md-9">
<h6 className="pt-2 float-left">{this.props.employers}</h6>
</div>
</div>
<h5 className="font-weight-bold pt-3 text-left">{this.props.slidercontents.Description}</h5>
<h5 className="font-weight-bold pt-3 text-left ">{this.props.slidercontents.RatePerHour}</h5>
<div className="row pt-3">
<div className="col-md-2">
<div><i class="fas fa-map-marker-alt"></i></div>
</div>
<div className="col-md-5">
<p className="float-left">{this.props.slidercontents}</p>
</div>
<div className="col-md-5">
<p className="float-right">5 mins ago</p>
</div>
</div>
</div>
);
}
}
But the props stays undefined.... any help on how to access the state values?
Pass the parent component's state as props to the child component (in the render function):
render() {
return <Slidercontent employers={this.state.employers}
}
This way, you can access the employers in the child component by:
{this.props.employers}

Resources