I am new to react and trying to understand how to debug and figure out how/why query trim is not a function below:
Full code:
import React, { Component } from 'react';
import {BrowserRouter as Router} from 'react-router-dom';
import { Link } from 'react-router-dom';
import * as BooksAPI from './data/BooksAPI';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
const BookSearch = observer(class BookSearch extends Component{
state = observable({
query: '',
books: []
})
searchBooks = (query) =>{
this.setState({ query: query.trim() }); <----- here
BooksAPI.search(query, 20).then((books) =>{
console.log(books);
this.setState({ books: books });
})
}
render(){
const { query } = this.state;
const bookSearch = this.state.books.map((book) =>
<li key={book.id}>
<div className="book">
<div className="book-top">
<div className="book-cover" style={{ width: 128, height: 193, backgroundImage: `url(${ book.imageLinks.thumbnail })` }}></div>
<div className="book-shelf-changer">
<select onChange={(event) => this.props.bookChange(book, event.target.value)}>
<option>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 className="book-title">{ book.title }</div>
<div className="book-authors">{ book.authors.map((author) =>
<span key={ author + book.title } >{ author }</span>
)}</div>
</div>
</li>
) ;
return(
<Router>
<div className="App">
<div className="search-books">
<div className="search-books-bar">
<Link className="close-search" to='/'>Close</Link>
<div className="search-books-input-wrapper">
<input
type="text"
placeholder="Search by title or author"
onChange={ this.searchBooks}
/>
</div>
</div>
<div className="search-books-results">
<div className="bookshelf">
<h2 className="bookshelf-title">{ this.state.query }</h2>
<div className="bookshelf-books">
<ol className="books-grid">
{ bookSearch }
</ol>
</div>
</div>
</div>
</div>
</div>
</Router>
)
}
})
export default BookSearch
The onChange handler of an <input> component gets passed an event (which is a react synthetic event instance) rather than just the value of the input:
You can access the actual value via event.target.value:
searchBooks = (event) =>{
this.setState({ query: event.target.value.trim() });
// ...
}
Related
I'm having a problem, which is to bring the weather information of a city where the user typed in the input, to my component.
I managed to make it so that when the user typed the city or country, it was already entered as a parameter in my api, but the weather information only appears when I CTRL+S my tsx file.
The same follows in the codes and images below
CityWeatherSearch.tsx
import { MagnifyingGlass } from 'phosphor-react'
import { FormEvent, useRef, useState } from 'react';
import * as Styled from './style'
interface CityPropsP{
city:string,
setCity: typeof useState
}
export function CityWeatherSearch({city,setCity}:CityPropsP){
const inputRef = useRef<HTMLInputElement>(null);
function handleClick(event:FormEvent) {
event.preventDefault();
const inputCity = inputRef?.current?.value;
setCity(inputCity)
}
return(
<>
<Styled.BoxSearchCity>
<div className="headerSearch">
<form onSubmit={handleClick}>
<input type="text" placeholder='Procurar Cidade...' ref={inputRef} />
<button type="submit">
<MagnifyingGlass/>
</button>
</form>
</div>
<div className="bodySearch">
</div>
</Styled.BoxSearchCity>
</>
)
}
MainWeatherLive.tsx
import {Clock} from 'phosphor-react'
import { useState } from 'react'
import { useFetch } from '../../GetData/useFetch'
import * as Styled from './style'
type DataWeather = {
name: string,
condition:{
text:string,
icon:string
},
temp_c:number,
hour:[{
temp_c:number,
time:string,
condition:{
text:string,
icon:string
}
}]
}
interface CityPropsMain{
city:string,
}
export function MainWeatherLive({city}: CityPropsMain){
const {dataCurrent:dataCurrentApi, dataForecast:forecastApi}
= useFetch<DataWeather>(`/v1/forecast.json?key=aff6fe0e7f5d4f3fa0611008221406&q=${city}?days=1&aqi=no&alerts=no`);
console.log(city)
return(
<>
<Styled.HeaderBox>
<h6>Weather Now</h6>
</Styled.HeaderBox>
<Styled.Container>
{city == '' &&
<p>Carregando...</p>
}
<div className="mainInformation">
<div className="temperatura">
<span>{dataCurrentApi?.temp_c}º</span>
</div>
<div>
</div>
<div className="boxCidade">
<div className="cidade">
<span>{city}</span>
</div>
<div className="tempoHoras">
<span>
{new Date().toLocaleTimeString('pt-BR',{hour12:false, hour:'numeric',minute:'numeric'})} - {new Date().toLocaleDateString()}
</span>
</div>
</div>
<div className="iconeTem">
<img src={dataCurrentApi?.condition.icon} alt={dataCurrentApi?.condition.text} />
</div>
</div>
<div className="footerBox">
<div className="headerFooter">
<Clock/>
<span>Horários</span>
</div>
<div className="listaHorarios">
<ul className="boxTT">
{
forecastApi?.hour?.map(weatherA =>{
const hourTemp = weatherA.time.split(" ")[1].replace(":00","");
const hourTempNumber:number = +hourTemp;
const hourNow = new Date().getHours();
return(
<>
{
hourTempNumber == hourNow &&
<li>
<div className="titulo" key={weatherA.temp_c}>
<span>{hourTempNumber}</span>
</div>
<div className="temperatura">
<img src={weatherA.condition.icon} alt={weatherA.condition.text} />
<span>{dataCurrentApi?.temp_c}º</span>
</div>
</li>
}
{
hourTempNumber > hourNow &&
<li>
<div className="titulo" key={weatherA.temp_c}>
<span>{hourTempNumber}</span>
</div>
<div className="temperatura">
<img src={weatherA.condition.icon} alt={weatherA.condition.text} />
<span>{weatherA.temp_c}º</span>
</div>
</li>
}
</>
)
})
}
</ul>
</div>
</div>
</Styled.Container>
</>
)
}
Weather.tsx
import { CityWeatherSearch } from "./WeatherC/CityWeatherSearch";
import { MainWeatherLive } from "./WeatherC/MainWeatherLive";
import { WeatherDetails } from "./WeatherC/WeatherDetails";
import coldImage from '../assets/cold.jpg'
import sunImage from '../assets/sun.jpg'
import rainImage from '../assets/rain.jpg'
import nightVideo from '../assets/night.mp4'
import night from '../assets/night.jpg'
import { useState } from "react";
export const TypesWeather = {
NIGHT:{
video:{
source: nightVideo
},
image:{
source: night
}
},
OVERCAST:{
video:{
source: nightVideo
},
image:{
source: night
}
},
COLD:{
image:{
source: coldImage,
title: 'Frio'
}
},
SUN:{
image:{
source: sunImage,
title: 'Verão'
}
},
RAIN:{
image:{
source: rainImage,
title: 'Chuva'
}
},
};
export type TypesWeatherV2 = keyof typeof TypesWeather;
export function Weather(){
const [city,setCity] = useState('');
return (
<>
<div className="globalSite" style={{background:`linear-gradient(to bottom,rgba(0,0,0,.85) 0,rgba(0,0,0,.85) 100%),url(${TypesWeather.RAIN.image.source})`}}>
</div>
<div className="boxAllWeather">
<div className="backgroundWeather" style={{backgroundImage:`url(${TypesWeather.RAIN.image.source})`}}></div>
<div className="boxAllInff">
<div className="mainWeather">
<MainWeatherLive city={city} />
</div>
<div className="otherInfoWeather">
<CityWeatherSearch city={city} setCity={setCity}/>
<WeatherDetails city={city} setCity={setCity} />
</div>
</div>
</div>
</>
)
}
When I search for a city or state and click search, the name appears normally, but without the updated information
When I save the component responsible for this information, it is updated
I don't know what to do, can anyone give me an idea?
I'm working on a checkbox filter in Reactjs application with backend Laravel I need to get a checkbox value on a check and add that value in API URL and then fetch data on the checkbox checked.
frontend Api
export const getFilteredPets = (Male, Female) => {
const data = {
Male, Female
}
return fetch(`${API}/pet/by/search?qp_pet_gender`, {
method:"POST",
headers:{
Accept: 'application/json',
"Content-Type":"application/json",
},
body:JSON.stringify(data)
})
.then(response =>{
console.log(response);
return response.json();
})
.catch(err=>{
console.log(err);
});
};
checkbox.js
import React, {useState, useEffect} from 'react';
const Checkbox = ({genders, handelFilters}) => {
const [checked, setChecked] = useState([]);
const handelToggle = g => () => {
const currentPetId = checked.indexOf(g)
const newCheckedPetId = [...checked];
if(currentPetId === -1){
newCheckedPetId.push(g)
}else{
newCheckedPetId.splice(currentPetId, 1)
}
//console.log(newCheckedPetId);
setChecked(newCheckedPetId)
handelFilters(newCheckedPetId);
}
return genders.map((g, i) =>(
<li key={i} className="list-unstyled">
<input onChange={handelToggle(g.name)} value={checked.indexOf(g.name === -1)} type="checkbox" className="form-check-input" />
<label className="form-check-label">{g.name}</label>
</li>
));
}
export default Checkbox;
listing.js
import React, {useState, useEffect} from 'react';
import Card from "./Card";
import WhySafari from "./WhySafari";
import Checkbox from "./Checkbox";
import Instagram from "./Instagram";
import Testimonial from "./Testimonial";
import Menu from "./Menu";
import Footer from "./Footer";
import {genders} from "./Genders";
import {getPuppies, getFilteredPets} from "./apiCore";
const Listing = () => {
const [myFilters, setMyFilters] = useState({
filters: { gender: [] }
});
const [error, setError] = useState(false);
const [male, setLimit] = useState('Male');
const [female, setSkip] = useState('Female');
const [size, setSize] = useState(0);
const [filteredResults, setFilteredResults] = useState([]);
const loadFilteredResults = newFilters => {
//console.log(newFilters);
getFilteredPets(male, female, newFilters).then(data => {
if(data.error){
setError(data.error);
}else{
setFilteredResults(data);
}
});
};
const handelFilters = (filters, filterBy) => {
console.log("Pet Gender", filters, filterBy);
const newFilters = {...myFilters};
newFilters.filters[filterBy] = filters;
setMyFilters(newFilters);
loadFilteredResults(myFilters.filters);
};
return(
<div>
<Menu/>
<div className="bradcam_area breadcam_bg">
<div className="container">
<div className="row">
<div className="col-lg-12">
<div className="bradcam_text text-center">
<h3>Puppies For Sale</h3>
<p>At Safari Stan’s you can rest assured that your new puppy is coming from a vetted,
responsible breeder. We are a community of dog lovers committed to helping you find the
perfect puppy for your experience level, family and home.
</p>
</div>
</div>
</div>
</div>
</div>
<section className="sample-text-area">
<div className="container">
<div className="row">
<div className="col-lg-3"></div>
<div className="col-lg-9 col-12">
<div className="listing-top-bar">
<div className="left-toggle"><i className="ti ti-filter"></i> Filter</div>
<div className="search-result">Showing 119 puppies out of 300 Puppies</div>
<div className="short-by">
<select className="cs-select cs-skin-elastic">
<option value="" disabled selected>Short By</option>
<option>Featured</option>
<option>Color</option>
<option>Name</option>
<option>Young to Old</option>
<option>Old to Young</option>
<option>Price Low to high</option>
<option>Price High to Low</option>
</select>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-3">
<div className="left-panel">
<div className="close-menu"><i className="ti ti-close"></i></div>
<div className="card">
<div className="card-main-header">
<h3 className="mt-0">Browser By:</h3>
</div>
<div className="card-header" role="tab" id="accordionHeadingOne">
<a data-toggle="collapse" data-parent="#accordion" href="#accordionBodyOne"
aria-expanded="ture" aria-controls="accordionBodyOne" className=" ">
Gender
<i className="ti ti-angle-down" aria-hidden="true"></i>
</a>
</div>
<div id="accordionBodyOne" className="card-body pl-0 collapse show" role="tabpanel"
aria-labelledby="accordionHeadingOne" aria-expanded="true" data-parent="accordion">
<ul className="unstyled centered">
<Checkbox genders={genders}
handelFilters={filters =>
handelFilters(filters, 'gender')}/>
</ul>
</div>
</div>
</div>
</div>
<div className="col-lg-9 col-md-9">
<div className="row">
{JSON.stringify(filteredResults)}
</div>
</div>
</div>
</div>
</section>
</div>
);
};
export default Listing;
I want when a check on checkbox my URL will b like ${API}/pet/by/search?qp_pet_gender=Male or ${API}/pet/by/search?qp_pet_gender=Female. I'm getting a checkbox value on checked Male, Female in console. Plase help me or guide me
What I am Trying to do is to fetch data from a Weather API on button click and when the data is fetched then that data should be mapped inside a component(i.e. Weather) and then only that component should appear on the screen, right now I am able to fetch the data but even then the component is not appearing.
Container.jsx
import React from 'react';
import './container.css'
import Weather from './weather';
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
location: "",
weather: []
};
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
componentDidMount() {
}
continue = (e) => {
const { location } = this.state;
const rawurl = 'http://api.weatherstack.com/current?access_key=d8fefab56305f5a343b0eab4f837fec1&query=' + location;
const url = rawurl;
//e.preventDefault();
if (location.length < 1) {
return alert('Enter the details');
}
else {
fetch(url)
.then(response => response.json())
.then(data =>{
this.setState({weather:data});
})
.catch(err => console.log("error ",err))
}
};
render() {
console.log(this.state);
const weather =
this.state.weather.length> 0 ?
this.state.weather.map(item => (<Weather location={item.location.name} temperature={item.current.temperature} weather={item.current.weather_descriptions[0]} windSpeed={item.current.wind_speed} windDegree={item.current.wind_degree} windDir={item.current.wind_dir} humidity={item.current.humidity} visibility={item.current.visibility} />
))
:<span></span>
return (
<div id="container">
<div class="searchicon">
<input type="search" placeholder="Enter City !!" type="text" name="location" value={this.state.location} onChange={this.handleChange}></input>
<label class="icon">
<button onClick={this.continue}><span class="fa fa-search"></span></button>
</label>
</div>
<div>
{weather}
</div>
</div>
);
}
}
export default Container;
Weather.jsx
import React from 'react';
class Weather extends React.Component {
render(){
return (
<div id="result">
<div id="location" class="insideres">
<div class="title">
Location
</div>
<div class="res">
{this.props.location}
</div>
</div>
<div id="Temperature" class="insideres">
<div class="title">
Temperature
</div>
<div class="res">
{this.props.temperature}
</div>
</div>
<div id="Weather" class="insideres">
<div class="title">
Weather
</div>
<div class="res">
{this.props.weather}
</div>
</div>
<div id="Windspeed" class="insideres">
<div class="title">
Wind Speed
</div>
<div class="res">
{this.props.windSpeed}
</div>
</div>
<div id="Wind_degree" class="insideres">
<div class="title">
Wind Degree
</div>
<div class="res">
{this.props.windDegree}
</div>
</div>
<div id="Wind_dir" class="insideres">
<div class="title">
Wind Direction
</div>
<div class="res">
{this.props.windDir}
</div>
</div>
<div id="Humidity" class="insideres">
<div class="title">
Humidity
</div>
<div class="res">
{this.props.humidity}
</div>
</div>
<div id="Visibility" class="insideres">
<div class="title">
Visibility
</div>
<div class="res">
{this.props.visibility}
</div>
</div>
</div>
);
}
}
export default Weather;
I want this weather component to appear when the data is fetched from the api, but right now data is being fetched but its not appearing.
In the above image you can see I am getting data from api, but not getting Weather component with that data under searchbar
Here is an update to your component using react with hooks. I highly suggest you adopt this pattern as it is way easier to work with, but does require using React 16 if you haven't adopted this yet. You will notice that I:
am using template strings instead of concatenating strings. This is best practice.
use async/await with promises
using an if statement to render the Weather component if the length of the weather variable in state is greater than 0. If it isn't, it will render the container component.
import "./container.css";
import React, { useState } from "react";
import Weather from "./weather";
const Container = () => {
const [location, setLocation] = useState("");
const [weather, setWeather] = useState([]);
const fetchWeatherData = async () => {
const url = `http://api.weatherstack.com/current?access_key=d8fefab56305f5a343b0eab4f837fec1&query=${location}`;
if (location.length < 1) {
return alert("Enter the details");
} else {
await fetch(url)
.then((response) => response.json())
.then((data) => {
setWeather(data);
})
.catch((err) => console.log("error ", err));
}
};
if (weather.length > 0) {
return weather.map((item) => (
<Weather
location={item.location.name}
temperature={item.current.temperature}
weather={item.current.weather_descriptions[0]}
windSpeed={item.current.wind_speed}
windDegree={item.current.wind_degree}
windDir={item.current.wind_dir}
humidity={item.current.humidity}
visibility={item.current.visibility}
/>
));
}
return (
<div id="container">
<div className="searchicon">
<input
placeholder="Enter City !!"
type="text"
name="location"
value={location}
onChange={(e) => setLocation(e.target.value)}
/>
<label className="icon">
<button onClick={fetchWeatherData}>
<span className="fa fa-search" />
</button>
</label>
</div>
<div>{weather}</div>
</div>
);
};
export default Container;
I am creating a basic React app to hold books on certain shelves and am trying to create the functionality to move books between shelves.
The problem I have is that when I select the new target shelf from the book objects dropdown, the onUpdateShelf method in ListBooks.js does not seem to initiate the update and subsequent state change.
I am new to React, my understanding is that calling the setState function in updateShelf should trigger the re-render with the updated object.
My question then is, is my implementation wrong and where?
App.js
import React, { Component } from 'react'
import ListBooks from './ListBooks'
import * as BooksAPI from './utils/BooksAPI'
import { Route } from 'react-router-dom'
class BooksApp extends Component {
state = {
books: []
}
componentDidMount() {
BooksAPI.getAll()
.then((books) => {
this.setState(() => ({
books
}))
})
}
updateShelf = (book, shelf) => {
console.log(book)
console.log(shelf)
this.books.forEach(b => {
if(b.id === book.id && b.shelf !== book.shelf ) {
b.shelf = shelf
this.setState((currentState) => ({
books: currentState.books
}))
}
});
BooksAPI.update(book, shelf)
}
render() {
return (
<div>
<Route exact path='/' render={() => (
<ListBooks
books={this.state.books}
onUpdateShelf={this.updateShelf}
/>
)} />
</div>
)
}
}
export default BooksApp
And my ListBooks.js
import React, { Component } from 'react';
import PropTypes from 'prop-types'
import './App.css'
const shelves = [
{
key: 'currentlyReading',
name: 'Currently Reading'
},
{
key: 'wantToRead',
name: 'Want To Read'
},
{
key: 'read',
name: 'Read'
}
];
class ListBooks extends Component {
static propTypes = {
books: PropTypes.array.isRequired
}
state = {
showSearchPage: false,
query: ''
}
render() {
const { books, onUpdateShelf } = this.props
function getBooksForShelf(shelfKey) {
return books.filter(book => book.shelf === shelfKey);
}
console.log(books);
return(
<div className="app">
{this.state.showSearchPage ? (
<div className="search-books">
<div className="search-books-bar">
<a className="close-search" onClick={() => this.setState({ showSearchPage: false })}>Close</a>
<div className="search-books-input-wrapper">
{/*
NOTES: The search from BooksAPI is limited to a particular set of search terms.
You can find these search terms here:
https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md
However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
you don't find a specific author or title. Every search is limited by search terms.
*/}
<input type="text" placeholder="Search by title or author"/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid"></ol>
</div>
</div>
) : (
<div className="list-books">
<div className="list-books-title">
<h1>My Reads</h1>
</div>
<div className="list-books-content">
<div>
{ shelves.map((shelf) => (
<div key={shelf.key} className="bookshelf">
<h2 className="bookshelf-title">{shelf.name}</h2>
<div className="bookshelf-books">
<ol className="books-grid">
<li>
{ getBooksForShelf(shelf.key).map((book) => (
<div key={book.id} className="book">
<div className="book-top">
<div className="book-cover" style={{ width: 128, height: 193, backgroundImage: `url(${book.imageLinks.thumbnail})` }}></div>
<div className="book-shelf-changer">
<select>
<option value="none" disabled>Move to...</option>
<option value="currentlyReading" onClick={() => onUpdateShelf(book, 'currentlyReading')} >Currently Reading</option>
<option value="wantToRead" onClick={() => onUpdateShelf(book, 'wantToRead')} >Want to Read</option>
<option value="read" onClick={() => onUpdateShelf(book, 'read')} >Read</option>
<option value="none" onClick={() => onUpdateShelf(book, '')} >None</option>
</select>
</div>
</div>
<div className="book-title">{book.title}</div>
<div className="book-authors">{book.author}</div>
</div>
))}
</li>
</ol>
</div>
</div>
)) }
</div>
</div>
<div className="open-search">
<a onClick={() => this.setState({ showSearchPage: true })}>Add a book</a>
</div>
</div>
)}
</div>
)
}
}
export default ListBooks
When you passe updateShelf to your component ListBooks, you lose the value of this inside updateShelf, and as a result this.books will be undefined.
You can solve this by, either doing this inside the constructor of BooksApp :
this.updateShelf = this.updateShelf.bind(this)
Or by using arrow functions:
<Route exact path='/' render={() => (
<ListBooks
books={this.state.books}
onUpdateShelf={() => { this.updateShelf()} }
/>
)} />
EDIT
You are already using arrow functions inside BooksApp, so what I said before isn't necessary.
But still, you should use this.state.books and not this.books inside updateShelf.
My render method is as follows
render() {
const language = this.props.language.default.portal;
const currentUserEmail = getUserEmail();
let cars = carData.filterCars(this.props.carsToShow, this.props.filters);
return (
<div className="contentRight noPadding col-xl-10 col-lg-10 col-md-10 col-sm-9 col-xs-7">
<div className="cars" style={{position: 'relative'}}>
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500} transitionEnterTimeout={500} transitionLeaveTimeout={500}>
<div>
{this.showMsg(cars)}
<Shuffle>
{cars.map((car, i) => {
const initialReg = car.initialRegistration.slice(0,3) + car.initialRegistration.slice(6,10);
// str.slice(1, 4) extracts the second character through the fourth character (characters indexed 1, 2, and 3)
return (
<div key={car.chassis} className="carBox noPadding" style={{position: "relative"}}>
<div className="carBoxContent">
<PhotoAndFavorites car={car} language={language} favoriteActions={this.props.actionFavorites} favorites={this.props.favorites}/>
<div className="carNameAndDesc">
<div><Link to="" style={{textDecoration: 'none'}}>{car.make} {car.model}</Link></div>
<div>{car.desc}</div>
</div>
<div className="carPrice">
<div>{car.price}</div>
<div>{car.btw}</div>
</div>
<div className="extraFeatures" style={{marginBottom: 5, backgroundColor: '#eee'}}>
</div>
<div className="mainFeatures">
<div><img src="../images/portal/user/status/fuel-icon.png" style={{height: 12}}/> <span>{car.fuel}</span></div>
<div><img src="../images/portal/user/status/road-icon.png" style={{height: 12}}/> <span>{car.mileage}</span></div>
<div><img src="../images/portal/user/status/calendar-icon.png" style={{height: 12}}/> <span>{initialReg}</span></div>
</div>
<MakeOfferButton{...this.props} car={car}/><
</div>
</div>
);
})}
</Shuffle>
</div>
</ReactCSSTransitionGroup>
<div className="clearfix"/>
</div>
</div>
);
}
Redux connect is as follows :
function mapStateToProps(state, ownProps){
return {
filters: state.filters,
favorites: state.favorites,
carsToShow: state.carsToShow,
carsInCart: state.cart
};
}
function mapDispatchToProps(dispatch){
return {
actionFavorites: bindActionCreators(actionFavorites, dispatch),
actionsCart: bindActionCreators(actionCart, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(cars);
MakeOfferButton component is as follows :
import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import FontAwesome from 'react-fontawesome';
import {getUserEmail} from '../../../../components/homepage/login/getUserInfo';
import {cart_types} from './cars';
export default class MakeOffer extends React.Component {
constructor(props){
super(props);
this.state = {
offer: ""
}
}
componentWillReceiveProps(nextProps){
const car = this.props.car;
const userEmail = getUserEmail();
let offer = "";
if(nextProps.carsInCart.some(i => i.info.carID == car.id && i.info.user == userEmail)){
offer = parseInt(nextProps.carsInCart.filter(i => i.info.carID == car.id && i.info.user == userEmail).map(c => c.info.offer)[0]);
}
this.setState({offer: offer});
}
makeAnOffer(car, userEmail, event){
let dataToAdd = {type: cart_types.offer, info: {carID: car.id, user: userEmail, offer: this.state.offer}};
this.props.actionsCart.addToCart(dataToAdd);
}
removeOffer(car, userEmail, event){
let dataToRemove = {info: {carID: car.id, user: userEmail}};
this.props.actionsCart.removeFromCart(dataToRemove);
}
handleOfferChange(event){
(event.target.value < 1 ) ? this.setState({offer: ""}) : this.setState({offer: event.target.value});
}
render(){
const language = this.props.language;
const car = this.props.car;
const userEmail = getUserEmail();
return (
<div className="addToCardButton">
<div className="offerButtons" style={{postion: "relative"}}>
<button type="reset" className="btnReset" onClick={this.removeOffer.bind(this, car, userEmail)}><FontAwesome name="times"/></button>
<input type="number" pattern="[0-9]*" inputMode="numeric" placeholder="Your offer..." className="offerInput" value={this.state.offer} onChange={this.handleOfferChange.bind(this)}/>
<button type="submit" className="btnSubmit" onClick={this.makeAnOffer.bind(this, car, userEmail)}><FontAwesome name="check"/></button>
</div>
</div>
);
}
};
The problem is in MakeOfferButton component. The redux action is called when I call makeAnOffer function. That works fine.
But then componentWillReceiveProps should get the new props and update the state offer. And then that state should be shown in my input. But that isn't happening.
When I click on the second one, then it is shown. The first one and also the second one.
Why the state isn't showing first time?
Any advice?