Right now I'm stuck with pagination implementation with React. I have all the neccessary data from JSON, however I got no result.
Here's the code I use:
first, I fetch data from the server:
constructor() {
super();
this.state = {items: {}, totalPages: [], nextPage: []};
}
componentDidMount() {
let url = 'http://localhost:8000/items?json=true';
request.get(url).then((response) => {
this.setState({
items: response.body.items.data,
totalPages: response.body.items.last_page,
nextPage: response.body.items.next_page_url
});
});
}
Thus I get a simple JSON file:
{
"items": {
"total": 26025,
"per_page": 16,
"current_page": 1,
"last_page": 1627,
"next_page_url": "http://localhost:8000/items?page=2",
"prev_page_url": null,
"from": 1,
"to": 16,
"data": [
{
"id": 1,
...
},
{
"id": 2,
...
},
...
]
}
}
I successfully display items data in render method like this:
let items = _.map(this.state.items, (item) => {
return (
<div key={item.id}>
<div className="content">
<span>
{item.type}
</span>
...
</div>
</div>
)
});
and then return it like so:
return (
<div>
{items}
</div>
<div>
<a href={this.state.nextPage}>Next</a>
</div>
)
I can see that URL changes after I press Next button to page2 but there are two issues: I want to change items components based on JSON file when I click Next (i.e first page contains the first set of 16 elements, second page contains the second set) but there is no change and when I click Next button again but on the second page (according to URL) it doesn't get me to the third page and so on.
I know I need to somehow bind these state to page2 URL shows content described on the second page and I ran through tutorials but they seem to be outdated in case I use React 15.2.1.
I would appreciate any help or a thought that'd help me to solve it!
Add a click handler to your link element and pass the url as parameter. In the handler function make the ajax request and update the states using setState (similar to the one u did it on componentDidMount).
constructor() {
super();
this.state = {
items: [],
totalPages: '',
nextPage: ''
};
this._loadData = this._loadData.bind(this);
}
componentDidMount() {
const url = 'http://localhost:8000/items?json=true';
this._loadData(url);
}
_loadData(url) {
request.get(url).then((response) => {
this.setState({
items: response.body.items.data,
totalPages: response.body.items.last_page,
nextPage: response.body.items.next_page_url
});
});
}
render() {
let items = _.map(this.state.items, (item) => {
return (
<div key={item.id}>
<div className="content">
<span>
{item.type}
</span>
...
</div>
</div>
)
});
return (
<div>
{items}
</div>
<div>
<a href="#0" onClick={this._loadData(this.state.nextPage)}>Next</a>
</div>
)
}
Related
I am new to Vue.js, and I want to add a search function for my site. The data is from an API Call and is displayed using vue.js too.
Display HTML Code:
<div class="row" v-for="items in data">
<div class="col-lg-4 col-md-6" data-toggle="modal" data-target="#exampleModal" user="'items'" #click="sendInfo(items)">
<a href="#" class="latest-product__item">
<div class="latest-product__item__pic">
<img src="img/item_image_placeholder.jpg" alt="">
</div>
<div class="latest-product__item__text">
<h6>{{items.item_name}}</h6>
<div v-for="variant in items.variants">
<div v-for="store in variant.stores">
<span>{{store.default_price}}</span>
</div>
</div>
</div>
</a>
</div>
And here's my Vue.js:
window.onload = function () {
const access_token = "";
new Vue({
el: '#item-data',
data () {
return {
data:[],
selectedUser:'',
itemCart: [],
search:'',
quantity: '',
cartCheckout: []
}
},
mounted () {
axios.get('**api call here**', {
headers : {
Authorization: 'Bearer ' + access_token
},
params: {
limit: 250
}
})
.then((response) => {
// handle success
this.data = response.data.items
console.log(response);
removeLoader();
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
});
},
computed:{
cartItem(){
return store.getters.printCart;
},
count(){
return store.state.cartCount;
},
},
methods:{
sendInfo(items) {
this.selectedUser = items;
},
addCart: function(cartdets){
store.commit('addCart', cartdets);
store.commit('addCount', 1);
}
}
})
}
What I want now is to add a search function to my displayed items. I already added v-model to my input tag. The items are dynamically displayed using vue and I want a search function for specific items.
You could create a computed property, maybe name it something like filteredItems, and make it loop through all of your items and save the items you want to display into an array and then return that array.
Then in your html use a v-for to display the items from filteredItems.
I am learning RN and I am having trouble setting up a mapping method to go through an array of images of some players that I created in a local JSON file, and render them in their respective profile pages.
This is how I have set my json.
//PlayerImages.js
const PlayerImages = [
{
id: "1",
name: "Cristiano Ronaldo",
images:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "2",
name: "Lionel Messi",
images:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "3",
name: "Neymar",
images: mages:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "4",
name: "Gabriel de Jesus",
images:["https://i.pinimg.com/474x/f1/36/ca/f136ca04817e60fa12f4a5680101ff8b.jpg",
"https://i.pinimg.com/474x/b1/da/e2/b1dae2fe6ca1620e5d1949a2dcd33a0c.jpg",
"https://i.pinimg.com/564x/7b/53/32/7b5332ef6a981b3c54e855495ea1c828.jpg"]
},
{
id: "5",
name: "Roberto Firmino",
images:mages:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
}
]
export default PlayerImages;
This is how I have the ImageGallery component set up. Unfortunately, the way I have componentDidMount set up, shows Cristiano Ronaldos images in all profiles. How can I map it in order to make sure that each profile has the pictures of that particular player when you tap the gallery button on their profile?
//ImageGallery.js
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { SliderBox } from "react-native-image-slider-box";
import { withNavigation } from "react-navigation";
import PlayerImages from "../Data/PlayerImages";
class ImageGallery extends React.Component {
static navigationOptions = {
title: "Player Gallery",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: "bold"
};
constructor(props) {
super(props);
this.state = {
images: []
};
}
componentDidMount() {
let images = PlayerImages[0].images;
this.setState({ images });
}
render() {
return (
<View style={styles.container}>
<SliderBox
images={this.state.images}
sliderBoxHeight={900}
onCurrentImagePressed={index =>
console.warn(`image ${index} pressed`)
}
dotColor="yellow"
inactiveDotColor="white"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
export default withNavigation(ImageGallery);
Finally, when you are on the players profile, you should have access to their gallery by tapping the button in the header. As I mentioned earlier in the post, when you tap it, you get only the images of Cristiano Ronaldo.
//PlayerProfile.js
headerRight: (
<Button
onPress={() => navigation.navigate("ImageGallery")}
title="Gallery"
color="#f6c945"
/>
)
Pass the id of the player or the index of the player you want to display images of using navigation parameters , then use it to get the images of the player, right now you are using images at the 0th index of array.
componentDidMount() {
let images = PlayerImages[0].images;
this.setState({ images });
}
change this to
componentDidMount() {
let images = PlayerImages[index].images; //index is the index of the player whose images you want to show
this.setState({ images });
}
I'm trying to add and remove product when clicking a button, and each button is in different component and the data that I'm getting from is in storeData component where inside there is an object with a true/false status if the status is true the product should display in Cart component if false it will remove the product.
now in ProductList component when I click the add button the status is changing to true, but it's not changing the actual status in storeData component so the result when i go to Cart component nothing is displayed
I know I'm doing this the wrong way, so how can I perform this add and remove operation, i'm new in React.js so please any help would really be appreciated.
ProductList component
import itemlist from "../storeData/storeData";
import { Link } from "react-router-dom";
class ProductList extends Component {
state = {
items: itemlist.items,
addToCart: null
};
addItem(id) {
let itemArray = [];
itemlist.cartItems.filter(target => {
return id === target.id ? itemArray.push(target) : null;
});
const addToCart = itemArray[0];
addToCart.status = false;
this.setState({ addToCart });
}
render() {
return (
<div className="list-wrap">
{this.state.items.map(item => {
return (
<div key={item.id}>
<Link to={{ pathname: "/productdetail", itemdetail: item }}>
<img alt="item img" src={item.posterUrl} />
</Link>
<h2>{item.title}</h2>
<h3>${item.price}</h3>
<button onClick={() => this.addItem(item.id)}>Add to Cart</button>
</div>
);
})}
</div>
);
}
}
export default ProductList;
Cart component
import itemlist from "../storeData/storeData";
class Cart extends Component {
state = {
cart: itemlist.cartItems,
remove: null
};
removeItem(id) {
let itemArray = [];
itemlist.cartItems.filter(target => {
return id === target.id ? itemArray.push(target) : null;
});
let remove = itemArray[0];
remove.status = false;
this.setState({ remove });
}
render() {
return (
<div>
{this.state.cart.map(itm => {
return itm.status === false ? null : (
<div key={itm.id} className="cart-layout">
<img alt="img" src={itm.posterUrl} />
<h4>{itm.title}</h4>
<h4>{itm.price}</h4>
<button onClick={() => this.removeItem(itm.id)}>Remove</button>
</div>
);
})}
</div>
);
}
}
storeData component
let itemlist = {
items: [
{
id: 1,
title: "name 1",
price: "232",
posterUrl:
"https://images-na.ssl-images-amazon.com/images/M/MV5BMjIxNTU4MzY4MF5BMl5BanBnXkFtZTgwMzM4ODI3MjE#._V1_SX300.jpg"
},
{
id: 2,
title: "name 2",
price: "65",
posterUrl:
"https://images-na.ssl-images-amazon.com/images/M/MV5BMTY5NTc2NjYwOV5BMl5BanBnXkFtZTcwMzk5OTY0MQ##._V1_SX300.jpg"
},
],
cartItems: [
{
id: 1,
status: false,
title: "name 1",
price: "232",
posterUrl:
"https://images-na.ssl-images-amazon.com/images/M/MV5BMjIxNTU4MzY4MF5BMl5BanBnXkFtZTgwMzM4ODI3MjE#._V1_SX300.jpg"
},
{
id: 2,
status: false,
title: "name 2",
price: "65",
posterUrl:
"https://images-na.ssl-images-amazon.com/images/M/MV5BMTY5NTc2NjYwOV5BMl5BanBnXkFtZTcwMzk5OTY0MQ##._V1_SX300.jpg"
},
]
};
I don't think you are using filter correctly here, in either component. You are confusing the filter test with the action of composing your array. All you need with the filter is a test that will return a boolean and that will construct the array for you.
Try changing:
let itemArray = [];
itemlist.cartItems.filter(target => {
return id === target.id ? itemArray.push(target) : null;
});
To
const itemArray = itemlist.cartItems.filter(target => id === target.id);
And similarly in the cart component.
For more detail on filter see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
I want to map of over object instead of Array, my current code works great with Array map but I am getting data undefined if I map object using state props with redux.
My JSON Format:
{
"exclusive_collection": {
"id": "0",
"image_url": "media/mobilebanner/default/ExclusiveCollection-en_new.jpg"
},
"exclusive_brands": [
{
"id": "1268",
"is_featured": "0",
"name": "Spongelle",
"image_url": "media/catalog/category/Spongelle.jpg"
},
{
"id": "756",
"is_featured": "0",
"name": "Black Up",
"image_url": "media/catalog/category/Black-Up.jpg"
},
],}
Reducer function :
export function items(state = [], action) {
switch (action.type) {
case 'ITEMS_FETCH_DATA_SUCCESS':
return action.items;
default:
return state;
}
}
Child Component:
import React, { Component } from 'react';
import Slider from "react-slick";
class ShopbyCategory extends Component {
render() {
let shopbycategoryArray = [];
let shop_by_category = this.props.items.shop_by_category
for (let key in shop_by_category) {
shopbycategoryArray.push(shop_by_category[key]);
return (
<section className="celebrityslider">
<div className="row">
<div className="widget-title"><h3>Shop By Category</h3></div>
</div>
<div className="row">
<div className="col-md-12 no-padding">
<Slider {...slidersettings}>
{this.props.items.shop_by_category.map((item) => (
<div key={item.id} className="slider-item">
<img src={item.image_url} className="img-responsive"/>
</div>
))}
</Slider>
</div>
</div>
</section>
);
}
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
return (
null
);
}
}
I am able to get the data of exclusive_brands array with the code above in my component.
But I am not sure how to get the data of exclusive_collection I am always getting undefined if I am doing the below :
let exclusive_collection = this.props.items.exclusive_collection
console.log (exclusive_collection);
I would appreciate if someone can help me to map this with redux or in other way. Thanks
could you please tell me how to render a list in react js.
I do like this
https://plnkr.co/edit/X9Ov5roJtTSk9YhqYUdp?p=preview
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
hello
</div>
);
}
}
You can do it in two ways:
First:
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>);
return (
<div>
{listItems }
</div>
);
}
Second: Directly write the map function in the return
render() {
const data =[{"name":"test1"},{"name":"test2"}];
return (
<div>
{data.map(function(d, idx){
return (<li key={idx}>{d.name}</li>)
})}
</div>
);
}
https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions
You can pass any JavaScript expression as children, by enclosing it within {}. For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [{name: 'bob'}, {name: 'chris'}],
};
}
render() {
return (
<ul>
{this.state.data.map(d => <li key={d.name}>{d.name}</li>)}
</ul>
);
}
}
ReactDOM.render(
<First />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Shubham's answer explains very well. This answer is addition to it as per to avoid some pitfalls and refactoring to a more readable syntax
Pitfall : There is common misconception in rendering array of objects especially if there is an update or delete action performed on data. Use case would be like deleting an item from table row. Sometimes when row which is expected to be deleted, does not get deleted and instead other row gets deleted.
To avoid this, use key prop in root element which is looped over in JSX tree of .map(). Also adding React's Fragment will avoid adding another element in between of ul and li when rendered via calling method.
state = {
userData: [
{ id: '1', name: 'Joe', user_type: 'Developer' },
{ id: '2', name: 'Hill', user_type: 'Designer' }
]
};
deleteUser = id => {
// delete operation to remove item
};
renderItems = () => {
const data = this.state.userData;
const mapRows = data.map((item, index) => (
<Fragment key={item.id}>
<li>
{/* Passing unique value to 'key' prop, eases process for virtual DOM to remove specific element and update HTML tree */}
<span>Name : {item.name}</span>
<span>User Type: {item.user_type}</span>
<button onClick={() => this.deleteUser(item.id)}>
Delete User
</button>
</li>
</Fragment>
));
return mapRows;
};
render() {
return <ul>{this.renderItems()}</ul>;
}
Important : Decision to use which value should we pass to key prop also matters as common way is to use index parameter provided by .map().
TLDR; But there's a drawback to it and avoid it as much as possible and use any unique id from data which is being iterated such as item.id. There's a good article on this - https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
Try this below code in app.js file, easy to understand
function List({}) {
var nameList = [
{ id: "01", firstname: "Rahul", lastname: "Gulati" },
{ id: "02", firstname: "Ronak", lastname: "Gupta" },
{ id: "03", firstname: "Vaishali", lastname: "Kohli" },
{ id: "04", firstname: "Peter", lastname: "Sharma" }
];
const itemList = nameList.map((item) => (
<li>
{item.firstname} {item.lastname}
</li>
));
return (
<div>
<ol style={{ listStyleType: "none" }}>{itemList}</ol>
</div>
);
}
export default function App() {
return (
<div className="App">
<List />
</div>
);
}
import React from 'react';
class RentalHome extends React.Component{
constructor(){
super();
this.state = {
rentals:[{
_id: 1,
title: "Nice Shahghouse Biryani",
city: "Hyderabad",
category: "condo",
image: "http://via.placeholder.com/350x250",
numOfRooms: 4,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 43
},
{
_id: 2,
title: "Modern apartment in center",
city: "Bangalore",
category: "apartment",
image: "http://via.placeholder.com/350x250",
numOfRooms: 1,
shared: false,
description: "Very nice apartment in center of the city.",
dailyPrice: 11
},
{
_id: 3,
title: "Old house in nature",
city: "Patna",
category: "house",
image: "http://via.placeholder.com/350x250",
numOfRooms: 5,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 23
}]
}
}
render(){
const {rentals} = this.state;
return(
<div className="card-list">
<div className="container">
<h1 className="page-title">Your Home All Around the World</h1>
<div className="row">
{
rentals.map((rental)=>{
return(
<div key={rental._id} className="col-md-3">
<div className="card bwm-card">
<img
className="card-img-top"
src={rental.image}
alt={rental.title} />
<div className="card-body">
<h6 className="card-subtitle mb-0 text-muted">
{rental.shared} {rental.category} {rental.city}
</h6>
<h5 className="card-title big-font">
{rental.title}
</h5>
<p className="card-text">
${rental.dailyPrice} per Night · Free Cancelation
</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
}
export default RentalHome;
Try this:
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
{listItems}
</div>
);
}
}