Passing picture from one component to another in React - javascript

I have a product component which I wish to pass its picture to another component, my picture is uploaded from Rails backend, and the product details are mapped. What I want to achieve is when you click on the button then your product picture will display in the design page to be custom design.
import axios from 'axios';
import CardDeck from 'react-bootstrap/CardDeck';
import Card from 'react-bootstrap/Card';
import {Link} from 'react-router-dom';
import Display from './Display';
const SERVER_URL = "http://localhost:3000/products/index";
const IMAGE_URL = "http://localhost:3000/";
class Product extends Component {
constructor(props) {
super(props);
console.log(props);
this.state = {
products: [],
name: '',
material: ''
}
}
fetchProducts () {
axios.get(SERVER_URL).then((res) => {
//console.log(res.data);
const allProducts = res.data;
//this.setState({product: []});
this.setState({products: res.data});
this.setState({material: res.data.id});
// const aProduct = [...new Set(allProducts.map(pro => pro.name))]
// console.log(aProduct);
})
}
componentDidMount(){
this.fetchProducts();
}
_handleClick = event => {
event.preventDefault();
axios.get(SERVER_URL,{
//product:{name: this.state.name, category: this.state.category}
}).then(res =>{
this.setState({
})
}).catch(error => {console.log(error);
});
}
render() {
return (
<div className="productGrid">
{this.state.products.map((product, index) => (
// <p>Name: {product.name} <p>Price:{product.price}</p> <p>Category:{product.category}</p>
// <p> Fixing Method:{product.fixing_method}</p> <p>Material:{product.material}</p>
// <p>Height:{product.height}</p>
<CardDeck>
<Card>
<Card.Img variant="top" src={IMAGE_URL + product.img_tag} />
<Card.Body>
<Card.Title>Name: {product.name}</Card.Title>
<Card.Text>Category: {product.category}</Card.Text>
<Card.Text>Price: ${product.price}</Card.Text>
<Card.Text>Material: {product.material}</Card.Text>
<Card.Text>Fixin Method: {product.fixing_method}</Card.Text>
<Card.Text>Shape: {product.shape}</Card.Text>
<Card.Text>Height: {product.height}</Card.Text>
<Card.Text>Width: {product.width}</Card.Text>
<Link to={"/DesignPage/" + product.id}><button >Design Me</button></Link>
</Card.Body>
</Card>
</CardDeck>
))}
<Display image={IMAGE_URL + product.img_tag}/>
</div>
);
}
}
export default Product;
Design Page
When you click on design me button then based on the product the picture of that product should appear in design page
import React, { Component } from 'react';
import SideBar from './SideBar';
import Nav from './Nav'
import Display from './Display';
class DesignPage extends Component {
constructor(props) {
super(props);
// console.log(props.match.params.design);
this.state = { }
}
render() {
return (
<div><Nav/>
<div className="container py-4">
<div className="row">
<div className="col-lg-5">
<SideBar/>
</div>
<div className="col-lg-6">
{/* <Display design={this.props.match.params.design}/> */}
<Display/>
</div>
</div>
</div>
</div>
);
}
}
export default DesignPage;
Display
import React from 'react';
import Product from './Product';
const Display = (props) => {
console.log(props.design);
return(
<div className="card card-content">
<div className="container-lg">
<div>{props.design}</div>
</div>
</div>
)
}
export default Display;

Access like props.image instead of props.design as i can see you are assigning your concatenating url to image in Product component.
const Display = (props) => {
console.log(props.image);
return(
<div className="card card-content">
<div className="container-lg">
<div>{props.image}</div>
</div>
</div>
)
}

Related

React value returning as undefined

I am trying to map through the data in context and render out a list of cars. But I keep running into some sort of error. I would like to be able to select one of the cars and have it navigate me to another page that displays more details of the car. Current error is (TypeError: value.state.car is undefined). Any help would be great! Current code
Context.js
import React, {Component } from 'react';
import { carInventory } from './data';
export const MyContext = React.createContext();
export class MyProvider extends Component {
state = {
cars: []
};
componentDidMount() {
this.setCars();
}
setCars = () => {
let tempProducts = [];
carInventory.forEach(item =>{
const singleItem = {...item};
tempProducts = [...tempProducts,singleItem];
})
this.setState(()=>{
return {cars:tempProducts}
})
}
getItem = (id) => {
const car = this.state.cars.find(item => item.id === id);
return car;
}
handleDetail = (id) =>{
const car = this.getItem(id);
this.setState(()=>{
return {detailProduct:car}
})
}
render() {
return (
<MyContext.Provider value={{
state: this.state,
handleDetail: this.handleDetail}}>
{this.props.children}
</MyContext.Provider>
)
}
}
VehicleList.js
import React, { Component } from "react"
import './App.css';
import Vehicles from "./Vehicles"
import { MyProvider, MyContext } from "./Context";
export default class VehicleList extends Component {
render() {
return (
<div className="vehicles">
<div className="showcase">
<MyContext.Consumer>
{(value) => (
<React.Fragment>
{value.state.car.map(car => {
return (
<Vehicles key={car.id} car=
{car} />
);
})}
</React.Fragment>
)}
</MyContext.Consumer>
</div>
</div>
)
}
}
import React, { Component } from 'react';
import './App.css';
import { MyProvider, MyContext } from "./Context";
import { Link } from 'react-router-dom';
class Vehicles extends Component {
render() {
const { make, model, id, info, img } = this.props.cars
return (
<div className="col-9 mx-auto col-md-6 col-lg-3 my-3">
<div className="card">
<MyContext.Consumer>
{(value) => (<div className="img-container p-5"
onClick={() =>{
value.handleDetail(id)
}}>
<Link to="/VehicleOverview">
<img src={img} alt="product" className="card-img-top"/>
</Link>
</div>)}
</MyContext.Consumer>
</div>
</div>
)
}
}
export default Vehicles;
This is the kind of thing where static type checkers can really save you some grey hairs.
Your context indeed does not have any property car.
It does, however, have a property cars.
So you should map over cars, i.e. value.state.cars.map(car => ...)
:)

React: How to redirect

I am a beginner in React and was implementing a function where on a button click in the render method, I go to a function foo. In that function, I am sending the username and password to a server.
If the username and password are correct, it returns a JSON object like
{"Result":1,"Cookie":"COOKIE!!!"}
I am trying to redirect it to another class component I have made (Flood) if result is 1. Can someone kindly help me
I tried redirecting it after render and before return but I get an error
Error: Invariant failed: You should not use <Redirect> outside a <Router>
import React from 'react';
import './style.scss';
import LoginImage from './LoginImage.png'
import Button from 'react-bootstrap/Button'
import Form from 'react-bootstrap/Form'
import {Redirect, Router} from 'react-router-dom'
//import Logfailed from './Logfailed'
import Flood from './Flood'
class UserLogin extends React.Component {
constructor(props) {
super(props);
this.state = {userName:'', password:'', act:'l', flag:0, txt:''};
this.handleChange1 = this.handleChange1.bind(this);
this.handleChange2 = this.handleChange2.bind(this);
this.handleClick = this.handleClick.bind(this);
}
async handleClick(e) {
const url = 'http://52.8.557.164/user'
const data = {username:this.state.userName, password:this.state.password, action:this.state.act};
try {
const response = await fetch(url,
{
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
},
});
const json = await response.json();
if(json['Result'] === 1) {
this.setState({flag: 1, txt:''});
}
else {
this.setState({flag:2, txt:'Wrong username and Password'});
}
console.log('Success', JSON.stringify(json));
console.log(json['Cookie']);
} catch (error) {
console.error('Error', error);
}
}
handleChange1(e) {
this.setState({userName: e.target.value})
}
handleChange2(e) {
this.setState({password: e.target.value})
}
render() {
if (this.state.flag === 1) {
return <Redirect to='/Flood' />
}
return (
<div className = 'outer-container' ref={this.props.containerRef}>
<div className = 'header'> Login </div>
<div className="content">
<div className="image">
<img src={LoginImage} />
</div>
<Form className = 'form'>
<Form.Group controlId="formBasicEmail" className = 'form-group'>
<Form.Label style={{marginTop: '90px'}}>Username</Form.Label>
<Form.Text className="text-muted" htmlFor="username"></Form.Text>
<input type="text" value = {this.state.userName} name="username" placeholder="username" onChange={this.handleChange1}/>
</Form.Group>
<Form.Group controlId="formBasicPassword" className = 'form-group'>
<Form.Label>Password</Form.Label>
<Form.Text className="text-muted" htmlFor="password"></Form.Text>
<input type="password" value = {this.state.password} name="password" placeholder="password" onChange={this.handleChange2} />
<br></br>
<span>{this.state.txt}</span>
</Form.Group>
</Form>
</div>
<div className="footer">
<Button variant="outline-primary" size="lg" onClick={this.handleClick} className="btn" block>
Login
</Button>
</div>
</div>
);
}
}
export default UserLogin;
import React from 'react';
class Flood extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<h1>gg</h1>
)}
}
export default Flood;
import React from 'react';
import './App.css';
import UserLogin from './UserLogin';
import Register from './Register'
import { Router, Redirect} from 'react-router-dom'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
login: true
};
}
componentDidMount() {
this.rightSide.classList.add("right");
}
changeState() {
const { login } = this.state;
if (login) {
this.rightSide.classList.remove("right");
this.rightSide.classList.add("left");
} else {
this.rightSide.classList.remove("left");
this.rightSide.classList.add("right");
}
this.setState(prevState => ({ login: !prevState.login }));
}
render() {
const {login} = this.state;
const curr = login ? "Register" : "Login";
const currentActive = login ? "login" : "register";
return (
<div className="App">
<div className="login">
<div className="container" ref={ref => (this.container = ref)}>
{login && (
<UserLogin containerRef={ref => (this.curr = ref)} />
)}
{!login && (
<Register containerRef={ref => (this.curr = ref)} />
)}
</div>
<RightSide
curr={curr}
currentActive={currentActive}
containerRef={ref => (this.rightSide = ref)}
onClick={this.changeState.bind(this)}
/>
</div>
</div>
);
}
}
const RightSide = props => {
return (
<div
className="right-side"
ref={props.containerRef}
onClick={props.onClick}
>
<div className="inner-container">
<div className="text">{props.curr}</div>
</div>
</div>
);
};
export default App;
BrowserRouter is the provider to be used in React Router for usage of anything related to routing. To add it to your component:
import { BrowserRouter as Router } from "react-router-dom";
class App extends React.Component {
render() {
return (
<Router>
// Rest of the App component here.
</Router>
);
}
}
Note that there needs to be only one wrapping Router in an application (generally) and hence it makes sense to wrap the entry component in it.
Basic Routing Example - React Routing
First of all, you need to wrap your component using withRouter tag
import { withRouter } from 'react-router-dom'
then wrap your component/class when you're exporting
export default withRouter(yourComponent);
ok, now back to the issue:
To redirect, you can simply push something to the history object
history.push('/redirect-location');

How to render the elements before to filter elements with ReactJS?

I'm doing a project which does a get of the json-server, and render them on the screen.
But when I added a filtering function on it, it only renders after I type a name to filter. I wanted him to render everyone and make the filter.
My Body.js (Where is my function of render):
import React from 'react';
import './Body.css';
import { Link } from "react-router-dom";
class Body extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
employeeBody: this.props.employee,
}
}
getName = () => {
const { employee, add } = this.props;
const {employeeBody} = this.state;
return employee.map(name => (
<div className='item'>
<Link className="link" to={`/user/${name.id}`}>
<div onClick={() => add(name)} key={name.id}>
<img className="img"
src={`https://picsum.photos/${name.id}`}
/>
</div>
<h1 className="name2"> {name.name} </h1>
</Link>
</div>
));
};
---
getValueInput = (evt) => {
const inputValue = evt.target.value;
this.setState({ input: inputValue });
this.filterNames(inputValue);
console.log(this.state.employeeBody)
}
filterNames (inputValue) {
const { employee } = this.props;
this.setState({
employeeBody: employee.filter(item =>
item.name.includes(inputValue))
});
}
---
render() {
return (
<div>
<div className="body">
{this.getName()}
</div>
<div className='input'>
<input type="text" onChange={this.getValueInput} />
</div>
</div>
)
}
}
export default Body;
My App.js (Where i get the state by get of axios.):
import React from 'react';
import {
BrowserRouter as Router,
Route
} from "react-router-dom";
import './App.css';
import axios from 'axios';
import Body from './Body';
import User from './User';
import Header from './Header';
class AppRouter extends React.Component {
state = {
employeeCurrent: [],
employee: []
};
componentDidMount() {
axios
.get("http://127.0.0.1:3004/employee")
.then(response => this.setState({
employee: response.data
}));
}
add = name => {
this.setState(prevState => {
const copy = prevState.employeeCurrent.slice(1);
copy.push(name);
return {
employeeCurrent: copy
};
});
};
render() {
return ( <
Router >
<
div className = "router" >
<
Header / >
<
Route exact path = "/"
render = {
props => ( <
Body { ...props
}
add = {
this.add
}
employee = {
this.state.employee
}
employeeCurrent = {
this.state.employeeCurrent
}
/>
)
}
/> <
Route path = "/user/:id"
component = {
props => ( <
User { ...props
}
employee = {
this.state.employee
}
employeeCurrent = {
this.state.employeeCurrent
}
/>
)
}
/> <
/div> <
/Router>
);
}
}
export default AppRouter;
Someone would can help me ?
You should filter in the render method.
render() {
const { employee: employees } = this.props; // rename the variable {employee} to plural {employees}, it has more sense.
const { input } = this.state;
return (
<div>
<div className="body">
{employees
.filter(employee => employee.name.includes(input))
.map(employee => {
<div className='item'>
<Link className="link" to={`/user/${employee.id}`}>
<div onClick={() => add(employee)} key={employee.id}>
<img className="img"
src={`https://picsum.photos/${employee.id}`}
/>
</div>
<h1 className="name2"> {employee.name} </h1>
</Link>
</div>
})}
</div>
<div className='input'>
<input type="text" onChange={(e) => this.setState({ input: e.target.value })} />
</div>
</div>
);
}
Remember that the method includes is case sensitive, it should be lowerCase it before to compare.
P.S.: You could also create a variable / component / function and render split all the "logic" of rendering there.

How to toggle class for the only one element on click in react

I am trying to make a flipped set of cards in React. You can see my code below. When I click on the card, they all flipped, but my goal is to flip only those that i clicked on. How can I do this?
This is my card component:
import React from 'react';
export default class Card extends React.Component {
render() {
let className = this.props.condition ? 'card-component flipped' : 'card-component';
return (
<div onClick={this.props.handleClick} className={className}>
<div className="front">
<img src={this.props.image} alt="card"/>
</div>
<div className="back">
</div>
</div>);
}
}
Here is my Deck component:
import React from 'react';
import Card from './Card.js';
const cardlist = require('../cardlist').cardlist;
export default class Deck extends React.Component{
constructor(props) {
super(props);
this.state = {flipped: false};
}
handleClick() {
this.setState({flipped: !this.state.flipped});
}
render() {
const list = this.props.cards.map((card, index) => {
return <Card
key={index}
handleClick={this.handleClick.bind(this)}
condition={this.state.flipped}
image={cardlist[card].path}
/>});
return(
<ul>
{list}
</ul>)
}
};
Thank you!
You can make use of indexes.
export default class Deck extends React.Component{
constructor(props) {
super(props);
//flipped true nonflipped false
this.state = {
flipStatus : props.cards.map((element) => false)
}
handleClick(index) {
const newflipStatus = [...this.state.flipStatus]
newflipStatus[index] = !this.state.flipStatus[index]
this.setState({flipStatus: newflipStatus);
}
render() {
const list = this.props.cards.map((card, index) => {
return <Card
key={index}
handleClick={this.handleClick.bind(this)}
condition={this.state.flipped}
index={index}
image={cardlist[card].path}
flipped=this.state.flipStatus[index]
/>});
return(
<ul>
{list}
</ul>)
}
};
here is your card component
export default class Card extends React.Component {
render() {
let className = this.props.condition ? 'card-component flipped' : 'card-component';
return (
<div onClick={() => this.props.handleClick(this.props.index)} className={className}>
{!flipped && <div className="front">
<img src={this.props.image} alt="card"/>
</div>}
{flipped && <div className="back">
</div>}
</div>);
}
}
in the handleClick function you are setting the "flipped" state variable for the whole deck not for a single card, that's why the whole deck changes together.
the solution would be simple to have a state for each card to designate if it's flipped or not, rather than making the variable on the parent level

How to update a parent's component state from a child component in Reactjs

I am passing the state of the parent component from the parent component to the child component.And in the child component,I have a different state.I am performing some actions on the child component's state and the result of that has to be added to the parent component's state.So,in my parent component I have written a callback function which will update the state of the parent component.The code is:
updateState = (booksList) => {
this.setState({books : this.state.books.push(booksList)});
}
So,this function is then passed to the child component as props:
<BookSearch
books={this.state.books}
handleShelfChange={this.handleShelfChange}
updateState={this.updateState}/>
Then in my child component,I am trying to implement the callback function as :
let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
this.props.updateState(getBook)
But this is not working as expected.Is this the correct way?Can anyone please help me with this?
I have tried to solve my problem by implementing the solution provided here : How to pass data from child component to its parent in ReactJS? , but I am getting some errors.
EDIT
Parent component : App.js
import React from 'react'
import * as BooksAPI from './BooksAPI'
import { Link } from 'react-router-dom'
import { Route } from 'react-router-dom'
import './App.css'
import BookList from './BookList'
import BookSearch from './BookSearch'
class BooksApp extends React.Component {
constructor(props) {
super(props);
this.state = {
books: [],
showSearchPage : false
};
//this.updateState = this.updateState.bind(this)
}
componentDidMount() {
BooksAPI.getAll().then((books) => {
this.setState({ books })
})
console.log(this.state.books);
}
filterByShelf = (bookName,shelfName) =>
bookName.filter(book => book.shelf===shelfName)
isTheBookNew = book => {
let is = false;
if (book.shelf === "none")
{ this.setState(state =>
{
books: state.books.push(book)});
is = true;
console.log(this.state.books);
}
return is;
};
handleShelfChange = (bookOnChange, newSehlf) => {
!this.isTheBookNew(bookOnChange) && this.setState(state => {
let newBooks = state.books.map(book =>
{ if (bookOnChange.id === book.id)
{ book.shelf = newSehlf; }
return book;
});
return {
books: newBooks
};
}
);
BooksAPI.update(bookOnChange, newSehlf);
};
updateState = (booksList) => {
const books = [...this.state.books, booksList]
this.setState({ books });
}
render() {
return (
<div className="app">
<Route exact path="/" render={() => (
<div className="list-books">
<div className="list-books-title">
<h1>MyReads</h1>
</div>
<BookList
books={this.filterByShelf(this.state.books,'currentlyReading')}
shelfName='Currently Reading'
handleShelfChange={this.handleShelfChange}/>
<BookList
books={this.filterByShelf(this.state.books,'wantToRead')}
shelfName='Want to Read'
handleShelfChange={this.handleShelfChange}/>
<BookList
books={this.filterByShelf(this.state.books,'read')}
shelfName='Read'
handleShelfChange={this.handleShelfChange}/>
<div className="open-search">
<Link
to="./search" />
</div>
</div>
)
} />
<Route path="/search" render={() =>
<BookSearch
books={this.state.books}
handleShelfChange={this.handleShelfChange}
updateState={this.updateState}/>
} />
</div>
)
}
}
export default BooksApp
BookSearch.js :
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import escapeRegExp from 'escape-string-regexp'
import sortBy from 'sort-by'
import * as BooksAPI from './BooksAPI'
import BookList from './BookList'
class BookSearch extends Component {
constructor(props) {
super(props);
this.state = {
search:'',
books:[]
}
}
updateSearch = (searchString) => {
this.setState({search: searchString.trim()})
let searchResults = BooksAPI.search(this.state.search,1).then((book_search) => {
if (book_search != undefined) {
console.log(book_search);
book_search.map((book) => book.shelf = 'none');
this.setState({ books : book_search }, this.check); // callback function to this.setState
console.log(this.state.books)
}
})
}
check = () => {
let parent_books = this.props.books;
console.log(this.state.books)
const book_result = this.state.books.map((book) => {
const parent = parent_books.find(parent => parent.title === book.title );
if(parent) {
//console.log(parent);
book.shelf = parent.shelf;
//console.log(book)
}
return book;
})
this.setState({books: book_result}, () => {console.log(this.state.books)})
}
updateParentState = () => {
let getBook = this.state.books.filter(filteredBook => filteredBook.shelf !== "none")
this.props.updateState(getBook)
}
render() {
return(
<div className="search-books">
<div className="search-books-bar">
<Link
to="/"
className="close-search">
Close
</Link>
<div className="search-books-input-wrapper">
<input
type="text"
placeholder="Search by title or author"
value={this.state.search}
onChange={(event) => this.updateSearch(event.target.value)}/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid">
<BookList
books={this.state.books}
handleShelfChange={this.props.handleShelfChange}
updateParentState={this.updateParentState}/>
</ol>
</div>
</div>
)
}
}
export default BookSearch
BookList.js
import React, { Component } from 'react';
import Book from './Book'
class BookList extends Component {
constructor(props) {
super(props);
this.state = {
showSearchPage : false
}
console.log(this.props.books)
}
render() {
return(
<div className="app">
<div>
<div className="list-books-content">
<div>
<div className="bookshelf">
<h2 className="bookshelf-title">{this.props.shelfName}</h2>
<div className="bookshelf-books">
<ol className="books-grid">
{this.props.books.map(book =>
<li key={book.title}>
<Book
book={book}
handleShelfChange={this.props.handleShelfChange}
update={this.props.updateParentState} />
</li>)
}
</ol>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
export default BookList;
Book.js
import React, { Component } from 'react'
class Book extends Component {
constructor(props) {
super(props);
this.props.updateParentState;
}
render() {
return(
<div className="book">
<div key={this.props.book.title}>
<div className="book-top">
<div className="book-cover" style={{width:128, height:193, backgroundImage: `url(${this.props.book.imageLinks.thumbnail})`}}>
<div className="book-shelf-changer">
<select id="bookName" value={this.props.book.shelf}
onChange={(event) => this.props.handleShelfChange(this.props.book, event.target.value)}>
<option value="moveTo" disabled>Move to...</option>
<option value="currentlyReading">Currently Reading</option>
<option value="wantToRead">Want to Read</option>
<option value="read">Read</option>
<option value="none">None</option>
</select>
</div>
</div>
</div>
<div className="book-title">{this.props.book.title}</div>
<div className="book-authors">{this.props.book.authors}</div>
</div>
</div>
)
}
}
export default Book
So, I have 4 components as shown above.From App component,I am calling BookSearch component where I can search for books and send the books to App component by selecting the value in dropdown. Each book in BookSearch component will initially be assigned a shelf property of "none".When a user selects a shelf value from Booksearch,the book will automatically be added to the App component.So,when I navigate back to the App component from BookSearch,I should be able to see the book in the assigned shelf.So,for this case,I am using the updateSearch function. The books are displayed through the Book component which has the dropdown value.
If i understood this correctly, you are mutating the state in the function updateState.
What you should be doing instead is,
const updateState = (booksList) => {
const books = [ ...this.state.books, ...booklist ];
this.setState({ books });
}
In parent component constructor add the following line:
this.updateState = this.updateState.bind(this)
More at https://reactjs.org/docs/handling-events.html

Categories