React js, How to get selected product name by id - reactjs

I need is to display selected product details, I am using React and Redux:
After selecting one product, in my ProductDetails page should be shown details of selected product. How should I properly make it in order to get and show product details
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { asyncConnect } from 'redux-connect';
import { connect } from 'react-redux';
import * as productActions from 'redux/modules/products';
#asyncConnect([{
promise: ({ store: { dispatch, getState }, params }) => {
dispatch(productActions.load({ id: params.prodId }, getState()));
}
}])
#connect(
state => ({
products: state.products.items
}),
{
...productActions
}
)
export default class ProductDetails extends Component {
static propTypes = {
products: PropTypes.array.isRequired
};
static defaultProps = {
products: []
};
state = {
products: []
}
render() {
const { products } = this.props;
return (
<div className="container">
<div className="row">
<div className="col-md-12">
<h1>Product details</h1>
<div className="col-xs-12">
<div className="row">
<div className="col-xs-4">
<div className="panel panel-default">
<div className="panel-body">
<p>{products.name}</p>// show selected product name
<p>{products.description}<p> // show selected product description
</div>
))}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}

I managed to solve the problem, it was very easy:
{products[0].name}
and
{products[0].description}

Related

React.js with Redux: Get info from state

I'm coding the app and I can't solve a problem. I have stored user info in the state (when I open Redux DevTools I can see the state -> user: {username: name, role: ...}).
Now in some components, I want to check if logged in user is admin or a user. I have it in that state but how can I load it in some class? When I export a function, I can use const userRole = useSelector(state => state.security.user.role_id); but in a class it makes a problem. Can you help me?
this is my code for User class and I want to show up DELETE button, only if user is an admin:
import React, {Component} from "react";
import PropTypes from "prop-types";
import {connect, useSelector} from "react-redux";
import { Link } from "react-router-dom";
import { deleteUser } from "../../store/actions/userActions";
class User extends Component{
constructor() {
super();}
onDeleteClick(id) {
this.props.deleteUser(id);
}
render() {
const { user } = this.props;
return (
<div className='row entry'>
<div className='col-sm-2'>
<span >{user.username}</span>
</div>
<div className='col-sm-2'>
<span >{user.name}</span>
</div>
<div className='col-sm-2'>
<span>{user.lastname}</span>
</div>
<div className='col-sm-2'>
<span>{user.tag}</span>
</div>
<div className='col-sm-1'>
<span>{user.pay}</span>
</div>
<div className='col-sm-1'>
<span>
{user.role_id}
</span>
</div>
<div className='col-sm-2'>
<Link to={`userlist/edituser:${user.id}`}>
<button><i className="fas fa-user-edit"></i></button>
</Link> | <button onClick={this.onDeleteClick.bind(this, user.id)}><i className="far fa-trash-alt"></i></button>
</div>
</div>
)
}
}
User.propTypes = {
deleteUser: PropTypes.func.isRequired
};
export default connect(
null, { deleteUser }
)(User);
With class components, you can make use of connect HOC with mapStateToProps to access state from redux
class User extends Component{
render() {
const { user, userRole } = this.props;
...
}
}
const mapStateToProps = (state) => {
return {
useRole: state.security.user.role_id,
}
}
export default connect(
mapStateToProps, { deleteUser }
)(User);

How do I reorder/sort Firebase data in React App?

So I'm flying by the seat of my pants here, and I need help reordering a data set. Here's the base of my react component. This is a personal project that I'm doing to then reuse at work for an actual project. The base of this came from a YouTube series about React + Firebase: https://www.youtube.com/playlist?list=PL4cUxeGkcC9iWstfXntcj8f-dFZ4UtlN3
Ideally, I'd like a set of buttons that will sort the data from asc or desc. And maybe dependent on some other things.
import React, { Component } from 'react';
import ShopList from '../shops/ShopList.js';
import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { firestoreConnect } from 'react-redux-firebase';
import { compose } from 'redux';
class Dashboard extends Component {
reOrder = (e) => {
e.preventDefault();
console.log("button works!");
}
render() {
const { shops } = this.props;
return(
<div className="dashboard container">
<Helmet>
<title>Dashboard | Indianapolis Coffee Guide</title>
</Helmet>
<div className="row">
<div className="col-sm-6">
<button className="btn btn-primary" onClick={this.reOrder}>Reorder</button>
</div>
</div>
<div className="row">
<ShopList shops={shops} />
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
shops: state.firestore.ordered.coffeeShops,
auth: state.firebase.auth
}
}
export default compose(
connect(mapStateToProps),
firestoreConnect([
{ collection: 'coffeeShops', orderBy: ['shopName', 'asc']}
])
)(Dashboard)
The data is being ordered right now at the end with the orderBy, but I need to be able to update that...
Thanks for your help!
I am not sure it would work, because I have never used react-redux-firebase, but it seems to me you could create a redux action that sets the ordering direction in redux store. Like this:
import React, { Component } from 'react';
import ShopList from '../shops/ShopList.js';
import { Helmet } from 'react-helmet';
import { connect } from 'react-redux';
import { firestoreConnect } from 'react-redux-firebase';
import { compose } from 'redux';
class Dashboard extends Component {
reOrder = (e) => {
e.preventDefault();
console.log("button works!");
const orderDirection = this.props.orderDirection === 'asc' ? 'desc' : 'asc';
this.props.dispatch(ReOderAction(orderDirection));
}
render() {
const { shops } = this.props;
return(
<div className="dashboard container">
<Helmet>
<title>Dashboard | Indianapolis Coffee Guide</title>
</Helmet>
<div className="row">
<div className="col-sm-6">
<button className="btn btn-primary" onClick={this.reOrder}>Reorder</button>
</div>
</div>
<div className="row">
<ShopList shops={shops} />
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
shops: state.firestore.ordered.coffeeShops,
auth: state.firebase.auth,
orderDirection: state.anything.orderDirection,
}
}
export default compose(
connect(mapStateToProps),
firestoreConnect([
{ collection: 'coffeeShops', orderBy: ['shopName', orderDirection]}
])
)(Dashboard)
Please, let me know if it worked...

ReactJS: Image not rendering

I am trying to render static images from images folder under src directory, however, it is not rendering, if i try to import any of the images directly and then pass in jsx like commented portion in images declaration it renders fine, also tried with backgroundImage property of css, it does not render anything.
import React, { Component } from 'react';
import Pizza from './components/pizza';
import './App.css';
class App extends Component {
state = {
open: false,
active: null,
categories: []
}
componentDidMount() {
this.setState({
categories
})
}
render() {
return (
<div className="App">
<Pizza data={this.state}/>
</div>
);
}
}
const categories = [
{"title":"Italian Pizza","link":"../images/italian-pizza.jpg",
"id":"586537da62981d5fb8c21617",
"details": "aksnflafiafoasofhafhoahfohaofhoahfhashfohasfhofhahsofohahosf"}
];
export default App;
pizza.js
import React from 'react';
import PropTypes from 'prop-types';
import italian from '../images/italian-pizza.jpg'
const Pizza = ({data}) => {
const images = data.categories.map((d,i) => {
return (
<div key={i}>
{/* <img src={italian} /> */}
<img src={`${d.link}`} />
</div>
)
});
return (
<div className="pizza">
<header className="header">Pizza</header>
<div className="main">
{data.categories.map((category, index) => {
return (
<div key={index}>
<ul className="items">
{images}
{/* <li style={{backgroundImage: `url(require(italian))`}} /> */}
</ul>
</div>
)
})}
</div>
</div>
)
}
Pizza.propTypes = {
categories: PropTypes.array,
open: PropTypes.bool,
active: PropTypes.bool
}
export default Pizza;

React: componentWillReceiveProps is not triggered when props change

I am new to react and its life-cycles, so currently following some tutorials and I am stuck with a problem that componentWillReceiveProps life-cycle method is not working the way I expect.
The thing is that in App component I am passing prop isActive to Card component, and it is changing its value when input checkbox checked/unchecked, so I expect componentWillReceiveProps life-cycle method to be triggered. However, this is not working at all. Maybe anything you can advice me on that case? As well as I am open for the best practice advice. Thank you for your time in advance.
Components code:
//App.js
import React, {Component} from 'react';
import Ticker from "./Ticker/Ticker";
import currencies from './currencies';
import Card from "./Card/Card";
import uuid from "uuid";
import 'bootstrap/dist/css/bootstrap.min.css';
import './App.css';
class App extends Component {
state = {
activePairs: []
};
handleCheckbox = (rateId, event) => {
const {checked} = event.target;
this.setState(({activePairs}) => {
let pairs = [...activePairs];
if (checked) {
if (!pairs.includes(rateId)) {
pairs.push(rateId);
}
} else {
let index = pairs.findIndex(rate => rate === rateId);
pairs.splice(index, 1);
}
return {
activePairs: pairs
};
});
};
render() {
return (
<div className="App">
<Ticker handleCheckbox={this.handleCheckbox.bind(this)}/>
<div className="container">
<div className="row">
{currencies.map(pair => <Card key={"card-" + uuid.v4()} currency={pair}
isActive={this.state.activePairs.includes(pair)}/>)}
</div>
</div>
</div>
);
}
}
export default App;
//Card.js
import React, {Component} from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../App.css';
class Card extends Component {
state = {
value: 0
};
componentWillReceiveProps(nextProp) {
console.log(nextProp);
if (!this.props.isActive && nextProp.isActive) {
this.updateExchangeRate();
this.interval = setInterval(this.updateExchangeRate, 3000);
} else if (this.props.isActive && !nextProp.isActive) {
clearInterval(this.interval);
this.setState({
value: 0
})
}
}
updateExchangeRate = () => {
return fetch(`https://www.cbr-xml-daily.ru/daily_json.js`).then(r => r.json()).then(res => {
let exRate = res["Valute"][this.props.currency.toUpperCase()]['Value'] + (Math.random() * (0.99 - 0.01 + 1) + 0.01);
let maximum = exRate + 5.00;
let minimum = exRate - 5.00;
this.setState({
value: (Math.floor(Math.random() * (maximum - minimum + 1)) + minimum).toFixed(2)
});
});
};
render() {
return (
<div className="col-md-3 col-sm-6 mb-3">
<div className="card text-center text-white bg-info">
<div className="card-header bg-info">{this.props.currency.toUpperCase() + " to RUB"}</div>
<div className="card-body">
<h5 className="card-title">Current exchange pair:</h5>
<p className="card-text">{this.state.value}</p>
</div>
</div>
</div>
);
}
}
export default Card;
//Ticker.js
import React, {Component} from 'react';
import currencies from "../currencies";
export default class Ticker extends Component {
state = {
currencies: currencies
};
render() {
return (
<div id="wrapper">
<div id="sidebar-wrapper">
<ul id="sidebar-ul" className="sidebar-nav">
{this.state.currencies.map(currency => {
return <li key={currency}>
<input id={currency + "-input"} type="checkbox" onChange=
{
this.props.handleCheckbox.bind(this, currency)
}/>
<label htmlFor={currency + "-input"} className="text-info"
role="button"> {currency.toUpperCase()} rate</label>
</li>
})}
</ul>
</div>
</div>
);
}
}
//currencies.js
export default ["aud", "azn", "gbp", "bgn", "usd", "eur"];
Well, I finally found what was causing the problem here. In App component I was using uuid module as a key prop for every Card component, so because of it that was always rendering a new Card component each time isActive props were updating.
Solution: use a constant id instead as a key prop.

Redux: re-rendering children on store state update

I have started to learn react + redux recently. Prior to that I have not had experience with this sort of stack.
So I ran into a problem where I do not understand why child components do not get re-rendered when reducer returns new state.
Full code on GITHUB
This is my parent component source on git:
import React from "react"
import {connect} from "react-redux"
import {fetchWarehouses} from "../../actions/warehouseActions"
import WarehouseMenu from "./WarehouseMenu"
import WarehouseView from "./WarehouseView"
import WarehouseEdit from "./WarehouseEdit"
#connect((store) => {
return {
warehouses: store.warehouses.warehouses,
selectedWarehouse: store.warehouses.selectedWarehouse,
isSelected: store.warehouses.isSelected,
warehouseCount: store.warehouses.warehouseCount,
}
})
export default class WarehousePage extends React.Component {
componentWillMount() {
this.props.dispatch(fetchWarehouses())
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-sm-2">
Warehouses ({this.props.warehouseCount}):
</div>
<div className="col-sm-10">
<WarehouseMenu warehouseList={this.props.warehouses} />
</div>
</div>
<div className="col-lg-12">
<WarehouseView test={this.props.isSelected} selectedWarehouse={this.props.selectedWarehouse} />
</div>
<div className="col-lg-12">
<WarehouseEdit />
</div>
</div>
)
}
}
And these are children source on git:
import React from "react"
import store from "../../store"
import {fetchOne} from "../../actions/warehouseActions"
export default class WarehouseMenu extends React.Component {
constructor(props) {
super(props)
}
select(id) {
store.dispatch(fetchOne(id))
}
render() {
const {warehouseList} = this.props.warehouseList
if (!warehouseList) {
return <button className="btn btn-success" key="new_warehouse">+</button>
}
const mappedWarehouses = warehouseList.map(wh => <button onClick={this.select.bind(this, wh.id)} className="btn btn-default" key={wh.id}>{wh.name}</button>)
mappedWarehouses.push(<button className="btn btn-success" key="new_warehouse">+</button>)
return (
<div className="btn-group">
{mappedWarehouses}
</div>
)
}
}
And source on git:
import React from "react"
import store from "../../store"
import {deleteWarehouse, fetchWarehouses} from "../../actions/warehouseActions"
export default class WarehouseView extends React.Component {
constructor(props) {
super(props)
}
render() {
const {test, selectedWarehouse} = this.props
if (!test) {
return null
}
return (
<div className="container-fluid">
<div className="row">
<div className="col-sm-2">
ID
</div>
<div className="col-sm-10">
{selectedWarehouse.id}
</div>
</div>
<div className="row">
<div className="col-sm-2">
Name
</div>
<div className="col-sm-10">
{selectedWarehouse.name}
</div>
</div>
<div className="row">
<div className="col-sm-12">
<button className="btn btn-warning">EDIT</button>
<button onClick={this.deleteWarehouse.bind(this, selectedWarehouse.id)} className="btn btn-danger">DELETE</button>
</div>
</div>
</div>
)
}
deleteWarehouse(id) {
store.dispatch(deleteWarehouse(id))
}
}
So whenever I dispatch deleteWarehouse I want WarehouseMenu to rerender since the state of store.warehouses.warehouses changes. I do not get the expected result. Only WarehousePage rerenders (e.g. store.warehouses.warehouseCount). I've tried #connectint store to child components but did not seem to get the desired result also.
You are not alterning the warehouses property inside your warehouseReducers.js when a DELETE_WAREHOUSE_FULFILLED action is dispatched, but you do alter the warehouseCount
Your delete action:
export function deleteWarehouse(id) {
return function (dispatch) {
axios.delete(`/api/sandy/api/warehouses/${id}`)
.then((response) => {
dispatch({
type: "DELETE_WAREHOUSE_FULFILLED",
payload: null
})
})
.catch((err) => {
})
}
}
never updates the state to remove the deleted warehouse from the state.warehouses array in warehouseReducers.js:
case "DELETE_WAREHOUSE_FULFILLED": {
return {...state,
selectedWarehouse: null,
isSelected: false,
warehouseCount: state.warehouseCount - 1
}
}

Resources