My React state doesn't stay on my components - javascript

In my code, I use a click event on the InterestBox in order to update the appearance of the InterestBox and to change the state of the parent of the parent of InterestBox.
However, when I inspect the element with the React Developer Tools or that I try to send a request to my API, the state.interests is always empty. But, when I log the state in the console, it shows an array with a length of 0, but containing all the proper values.
I tried to find what is wrong with my code, but I think I need an external look to find what is wrong.
import axios from 'axios';
import * as Cookies from 'js-cookie';
import React, { Component } from 'react';
import Button from '../../components/Button';
import Dashboard from '../Dashboard';
import ErrorContainer from '../../components/ErrorContainer';
import InterestList from '../../components/register/InterestList';
export class EditUser extends Component {
constructor(props) {
super(props);
this.state = {loading: true, interests: []}
this.addInterest = this.addInterest.bind(this);
this.logState = this.logState.bind(this);
}
addInterest(id, name) {
console.log('hoppity hippity you parenty')
var mid = 'm' + id;
console.log(this.state.interests[mid] == undefined)
if(this.state.interests[mid] == undefined) {
console.log(this.state);
this.setState((state) => {
state.interests[mid] = name;
return {interests: state.interests}
}, () => {
console.log(JSON.stringify(this.state.interests))
})
} else {
console.log('deleted')
var newInterest = this.state.interests;
delete newInterest[mid]
this.setState({interests: newInterest})
}
console.log(this.state.interests)
}
componentDidMount() {
var token = Cookies.get('token');
axios.get('http://localhost:8000/api/details', {headers: {"Accept": 'application/json', "Authorization": `Bearer ${token}`}}).then(
(success) => {
this.setState({
loading: false,
firstname : success.data.data.user.firstname,
lastname: success.data.data.user.lastname,
email: success.data.data.user.email,
dob: success.data.data.user.dob,
address: success.data.data.user.address,
uinterests: success.data.data.interests
})
}, (error) => {
this.props.history.push('/deconnexion');
}
)
var places = require('places.js');
var placesAutocomplete = places({
appId: "plZJLSHIW8M5",
apiKey: "0eddd2fc93b5429f5012ee49bcf8807a",
container: document.querySelector('#address-input')
});
}
logState() {
console.log(this.state);
}
render() {
return (
<Dashboard loading={this.state.loading}>
<h1 className="title">Modifier mon profil</h1>
<form className="user-form offer-update-form" onSubmit={this.handleSubmit}>
<label>Prénom :</label>
<input type="text" name="firstname" value={this.state.firstname} onChange={this.handleChange}></input> <br />
<label>Nom de famille :</label>
<input type="text" name="lastname" value={this.state.lastname} onChange={this.handleChange}></input> <br />
<label>Email :</label>
<input type="email" name="email" value={this.state.email} onChange={this.handleChange} /><br />
<label>Adresse :</label>
<input type="address" id="address-input" name="address" value={this.state.address} onChange={this.handleChange} /><br />
<label>Date de naissance :</label>
<input type="date" name="dob" value={this.state.dob} onChange={this.handleChange} /><br />
<InterestList alreadyChecked={this.state.uinterests} onClick={this.addInterest} />
<ErrorContainer errors={this.state.errors} />
<Button type="primary">Soumettre les changements</Button>
</form>
<Button type="danger" onClick={this.logState} />
</Dashboard>
)
}
}
export default EditUser
```
```
import React, { Component } from 'react'
import InterestBox from './InterestBox'
import Axios from 'axios'
export class InterestList extends Component {
constructor(props) {
super(props);
this.state = {pinterests: []}
this.pinterestRefs = React.createRef()
this.pinterestRefs.current = [];
}
componentDidMount() {
Axios.get('http://localhost:8000/api/interests')
.then((success) => {
this.setState({pinterests: success.data.data.interests});
})
}
componentDidUpdate(prevProps) {
console.log(JSON.stringify(prevProps));
console.log(JSON.stringify(this.props))
if(this.props.alreadyChecked != prevProps.alreadyChecked) {
this.props.alreadyChecked.forEach((item) => {
this.pinterestRefs.current.forEach((pinterest) => {
if(item == pinterest.props.id) {
console.log(pinterest)
pinterest.handleClick();
}
})
console.log(item)
})
}
console.log(this.pin)
}
render() {
return (
<React.Fragment>
{Object.keys(this.state.pinterests).map((interest, i) => {
var pinterest = this.state.pinterests[interest];
var callbackRef = node => this.pinterestRefs.current[i] = node;
return <InterestBox id={pinterest.id} onClick={this.props.onClick} icon={pinterest.picture_src} title={pinterest.name} ref={callbackRef} />
})}
</React.Fragment>
)
}
}
export default InterestList
```
```
import React, { Component } from 'react'
export class InterestBox extends Component {
constructor(props) {
super(props);
this.images = require('../../img/interests/*.svg');
this.state = {activated: false};
this.interest_box_content = React.createRef();
this.interest_text = React.createRef();
this.handleClick = this.handleClick.bind(this);
this.updateDimensions = this.updateDimensions.bind(this);
}
handleClick() {
console.log('hoppity hippity you clicky')
this.props.onClick(this.props.id, this.props.title);
this.setState(prevState => ({
activated: !prevState.activated
}))
}
updateDimensions() {
console.log((window.getComputedStyle(this.refs.interest_box_content).width))
this.refs.interest_text = (window.getComputedStyle(this.refs.interest_box_content).width)
}
render() {
return (
<div className="column is-one-fifth-desktop is-half-touch">
<div className="interest-box">
<div className="interest-box-adjuster">
<div ref={"interest_box_content"} className={"interest-box-content " + (this.state.activated == true ? 'interest-box-activated' : '')} onClick={this.handleClick}>
<img className="interest-icon" src={this.images[this.props.icon]} style={{'height': '50%'}}></img>
<i className="activated-icon fas fa-check"></i>
<span ref={"interest_text"} className="interest-text">{this.props.title}</span>
</div>
</div>
</div>
</div>
)
}
}
export default InterestBox
```

you have initialized interest as an array using []
but then, you are updating it as a map state.interests[mid] = name;
Note: JS is not type-safe. after the above statement, interests no longer remained an array
That's the reason why on console you are able to see it being populated but with an array length of 0. that's because you are outputting an object now and not an array.

Related

React class component state value not updating

I am new to react js. I am learning it by creating a simple app. I tried to create a simple weather app using react class component. All working fine but the result stored in a state variable is not printing in the template. I can see the API response in the console and then store the result on the 'currWeatherRes' state variable which is not showing in the template (Location is always blank)
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(){
super();
this.state = {
cityName: "",
currWeatherRes: {}
}
}
handleSubmit = (event) => {
event.preventDefault();
alert(`The name you entered was:`+ this.state.cityName);
fetch(`https://api.openweathermap.org/data/2.5/weather?q=`+this.state.cityName+`&appid=f3ee66722740d00cc6f197cbcab3d534`, {
method: 'GET'
}).then((response) => {
console.log(response)
this.setState({
currWeatherRes: response
})
//return response.json();
});
}
handleChange = (event) => {
this.setState({cityName:event.target.value});
}
render() {
return (
<div className="weather-app">
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.cityName} onChange={this.handleChange} placeholder="Enter City"/>
<button type="submit" value="Submit">Submit</button>
</form>
{(typeof this.state.currWeatherRes.main != "undefined") ? (
<div className="weather-details">
<div className="weather-location">
<div className="location">Loctaion: {this.state.currWeatherRes.name}</div>
</div>
</div>
):('')}
</div>
);
}
}
export default App;
The problem was not related to react but the way you handled API call.
Fix:
fetch(`https://api.openweathermap.org/data/2.5/weather?q=`+this.state.cityName+`&appid=f3ee66722740d00cc6f197cbcab3d534`, {
method: 'GET'
}).then((response) => {
return response.json();
}).then((res) => {
this.setState({
currWeatherRes: res
})
});
Working code:
import React, { Component } from 'react';
class App extends Component {
constructor(){
super();
this.state = {
cityName: "",
currWeatherRes: {}
}
}
handleSubmit = (event) => {
event.preventDefault();
alert(`The name you entered was:`+ this.state.cityName);
fetch(`https://api.openweathermap.org/data/2.5/weather?q=`+this.state.cityName+`&appid=f3ee66722740d00cc6f197cbcab3d534`, {
method: 'GET'
}).then((response) => {
return response.json();
}).then((res) => {
this.setState({
currWeatherRes: res
})
});
}
handleChange = (event) => {
this.setState({cityName:event.target.value});
}
render() {
console.log(this.state.currWeatherRes)
return (
<div className="weather-app">
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.cityName} onChange={this.handleChange} placeholder="Enter City"/>
<button type="submit" value="Submit">Submit</button>
</form>
{(typeof this.state.currWeatherRes.main != "undefined") ? (
<div className="weather-details">
<div className="weather-location">
<div className="location">Loctaion: {this.state.currWeatherRes.name}</div>
</div>
</div>
):('')}
</div>
);
}
}
export default App;

Why redux diff says that states are equal even though ther are not

For fun, I decided to write a booking app.
However ran into a problem when I get free rooms and send room data to TabComponent.js for the first time, everything works. But if I try to send the room data to TabComponent.js again, component does not update, but in redux devtools the state has changed. How to solve this problem? For more understanding, see the pictures below.
Component.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import PropTypes from "prop-types"
import { reservationCheck } from '../../../actions/axiosApi'
import { sendReservationProp } from '../../../actions/propActions'
class Form extends Component {
static propTypes = {
free_rooms: PropTypes.array.isRequired,
}
constructor(props) {
super(props)
this.state = {
arrival_date: '',
leaving_date: ''
}
}
handleChange = event => this.setState({ [event.target.name]: event.target.value });
handleSubmit = event => {
event.preventDefault()
this.props.reservationCheck(this.state)
}
sendFreeRoomPropToBookingTab = free_room => {
const reservation_prop = Object.assign(this.state, free_room)
this.props.sendReservationProp(reservation_prop) <--- sending room prop to tabComponent.js
}
render() {
const { arrival_date, leaving_date } = this.state
return (
<div className="booking-form-container">
<form onSubmit={this.handleSubmit}>
<input type="date" name="arrival_date" required onChange={this.handleChange} value={arrival_date} />
<input type="date" name="leaving_date" required onChange={this.handleChange} value={leaving_date} />
<button value="" type="submit">Find</button>
</form>
<div className="reservation-data-result">
{this.props.free_rooms.map(free_room => (
<div className="reservation-data-result__block" key={free_room.id}>
<img src={free_room.main_image} alt="" />
<div className="thumbnail-images">
{free_room.room_image.map(thumbnailImage => {
const [id, src] = thumbnailImage.split(': ')
return (
<div className="thumbnail-image">
<img src={src} key={parseInt(id, 10)}></img>
</div>
)
})}
</div>
<h3>{free_room.name}</h3>
<h5>price: {free_room.price}$</h5>
<a className="booking-btn">
<div className="btn-circle">
<div className="btn-arrow"></div>
</div>
<span className="btn-text" onClick={() => this.sendFreeRoomPropToBookingTab(free_room)}>Book room</span>
</a>
</div>
))}
</div>
</div>
)
}
}
const mapStateToProps = (state) => ({
free_rooms: state.roomReducer.free_rooms
})
export default connect(mapStateToProps, { reservationCheck, sendReservationProp })(Form)
action.js
import { RESERVATION_PROP } from './types'
export const sendReservationProp = reservation_prop => dispatch => {
dispatch({
type: RESERVATION_PROP,
payload: reservation_prop
})
}
reducer.js
import { GET_ROOM_DATA, RESERVATION_CHECK, RESERVATION_PROP } from '../actions/types'
const initialState = {
roomData: [],
free_rooms: [],
reservation_prop: {},
}
export default function (state = initialState, action) {
switch (action.type) {
case GET_ROOM_DATA:
return {
...state,
roomData: action.payload
}
case RESERVATION_CHECK:
return {
...state,
free_rooms: action.payload
}
case RESERVATION_PROP:
return {
...state,
reservation_prop: action.payload
}
default: {
return state
}
}
}
TabComponent.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
class BookingTab extends Component {
constructor(props) {
super(props)
this.state = {
room: this.props.reservation_prop.room,
price: this.props.reservation_prop.price,
arrival_date: this.props.reservation_prop.arrival_date,
leaving_date: this.props.reservation_prop.leaving_date,
name: '',
phone_number: ''
}
}
handleSubmit = () => {
console.log("SUBMIT!")
}
render() {
return (
<div className="booking-tab">
<div className="booking-tab-container">
<h2>Booking</h2>
<form onSubmit={this.handleSubmit}>
<h3>Room: {this.props.reservation_prop.name}</h3>
<h5>Price: {this.props.reservation_prop.price}$</h5>
<span>Arrival date: {this.props.reservation_prop.arrival_date}</span>
<span>Leaving date: {this.props.reservation_prop.leaving_date}</span>
<div className="name-input">
<input type="text" name="name" placeholder="Name" />
</div>
<div className="phone-number-input">
<input type="text" name="phone_number" placeholder="X (XXX) XXX-XX-XX" />
</div>
<button>Submit</button>
</form>
</div>
</div>
)
}
}
const mapStateToProps = state => ({
reservation_prop: state.roomReducer.reservation_prop
})
export default connect(mapStateToProps)(BookingTab)
This line const reservation_prop = Object.assign(this.state, free_room) actually modifies this.state and then sets reservation_prop to this.state.
So as long as this.state is not replaced by a completely new state, you will dispatch the same object multiple times and just modify it - which is something redux cannot detect, as stateBefore === stateAfter will hold true.
You probably want to do
const reservation_prop = Object.assign({}, this.state, free_room)
which creates a new object every time.

Uncaught TypeError: Object (…) is not a function

I am using Paystack component in my react app,
and the the component requires passing a kind of object containing some required
values below is the mother component for the one holding the paystackButton componenet.
import React from 'react';
import DateRangePicker from 'react-bootstrap-daterangepicker';
import { getRangeOfDates } from 'helpers';
import { BookingModal } from './BookingModal';
import * as moment from 'moment';
import * as actions from 'actions';
import { ToastContainer, toast } from 'react-toastify';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import PScomponent from '../payments/paystack'
class Booking extends React.Component {
constructor() {
super();
this.bookedOutDates = [];
this.dateRef = React.createRef();
this.state = {
errors:[],
proposedBooking: {
startAt: '',
endAt: '',
guests: '',
rooms: '',
totalPrice: '',
days:1
},
modal: {
open: false
}
}
}
............
render() {
const { rental, auth: {isAuth} } = this.props;
const { startAt, endAt, guests, rooms, totalPrice, days } =
this.state.proposedBooking;
const price = (parseInt(totalPrice)+5000) * parseInt(rooms)
const publicKey = "pk_test_........."
const amount = price * 100;
console.log(days)
const componentProps = {
email:this.props.auth.email,
amount,
metadata: {
userName : this.props.auth.username,
phone:this.props.auth.contact,
},
publicKey,
text: "Pay Now",
onSuccess: (e) =>
console.log(e),
onClose: () => alert("Wait! Don't leave :("),
}
//console.log(this.props.auth)
return (
<div className='booking' style={{marginBottom: '10px', padding: '0', border:'none'}}>
<ToastContainer />
<h3 className='booking-price'>NG{rental.dailyRate} <span className='booking-per-night'>per night</span></h3>
<hr></hr>
{ !isAuth &&
<Link className='btn btn-bwm btn-confirm btn-block' to={{pathname: '/login'}}>Login to book place!</Link>
}
{ isAuth &&
<React.Fragment>
<div className='form-group'>
<label htmlFor='dates'>Dates</label>
<DateRangePicker onApply={this.handleApply} isInvalidDate={this.checkInvalidDates} opens='left' containerStyles={{ display: 'block' }}>
<input ref={this.dateRef} id='dates' type='text' className='form-control'></input>
</DateRangePicker>
</div>
<div className='form-group'>
<label htmlFor='guests'>Guests</label>
<input value={guests} onChange={(event) => { this.selectGuests(event) }} type='number' className='form-control' id='guests' aria-describedby='emailHelp' placeholder=''></input>
</div>
<div className='form-group'>
<label htmlFor='guests'>Rooms</label>
<input value={rooms} onChange={(event) => { this.selectRoomNum(event) }} type='number' className='form-control' id='Rooms' aria-describedby='emailHelp' placeholder=''></input>
</div>
<button disabled={!startAt || !endAt || !guests} onClick={() => { this.confirmProposedData() }} className='contact_btn'>PAY FOR RESERVATION</button>
</React.Fragment>
}
{
this.state.modal.open && <PScomponent componentProps={componentProps}/>
}
</div>
)
}
}
function mapStateToProps(state){
return {
auth: state.auth
}
}
export default connect(mapStateToProps)(Booking)
inside PScomponent component .
import React from "react"
import {PaystackButton} from "react-paystack"
import "./P_Scomponent.css"
export default function PScomponent (props){
const { componentProps } = props;
//console.log(componentProps)
return (
<div className="P_Scomponent">
<PaystackButton className="paystack-button" {...componentProps} />
</div>
)
}
//
but yet the browser still give me the following error
i dont know where the error is coming from.
index.es.js:6 Uncaught TypeError: Object(...) is not a function
I finally got it working all I had to do was to downdate to a lower version of the react-paystack the version that worked for me is 2.0.2.

React Router will not redirect based on state

In the code, it reaches the isRegistered function, I know this as I have it console.log state. The state of registered is equal to true. So therefore based on the code it should redirect to /login but it is not.
import React from 'react'
import "./Register.css";
import {BrowserRouter as Route, Redirect, Link} from 'react-router-dom'
const initialUser = {
username: "",
email: "",
password: "",
password2: "",
name: ""
}
class Register extends React.Component {
constructor(props) {
super(props);
this.state = {
user: initialUser,
registered: ''
};
}
onUsernameChange = event => {
this.setState({ username: event.target.value });
};
onNameChange = event => {
this.setState({ name: event.target.value });
};
onEmailChange = event => {
this.setState({ email: event.target.value });
};
onPasswordChange = event => {
this.setState({ password: event.target.value });
};
onPassword2Change = event => {
this.setState({ password2: event.target.value });
};
isRegistered() {
const { registered } = this.state;
console.log(registered, 'here', this.state)
if (registered) {
return (
<Redirect to='/login' />
)
}
}
onRegister = () => {
fetch("http://localhost:3000/register", {
method: "post",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: this.state.name,
email: this.state.email,
username: this.state.username,
password: this.state.password,
password2: this.state.password2
})
})
.then(res => res.json())
.then(data => {
console.log(data.isRegistered);
if (data.isRegistered) {
this.setState({registered: true})
this.isRegistered();
}
})
};
render() {
return <div className="login-page">
<div className="form">
<form className="login-form">
<input type="text" placeholder="name" onChange={this.onNameChange} />
<input type="text" placeholder="username" onChange={this.onUsernameChange} />
<input type="text" placeholder="email" onChange={this.onEmailChange} />
<input type="password" placeholder="password" onChange={this.onPasswordChange} />
<input type="password" placeholder="confirm password" onChange={this.onPassword2Change} />
<button className="bluecolor" onClick={this.onRegister}>
Register
</button>
<p className="message">
Have an account? Login
</p>
</form>
</div>
</div>;
}
}
export default Register;
<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>
It reaches all the way to the if statement in isRegistered(). So I assume it is the redirect component that is wrong but I cannot figure it out for the life of me.
//UPDATE
This is now what I have in it
import React from 'react'
import "./Register.css";
import {BrowserRouter as Route, Redirect, withRouter} from 'react-router-dom'
const initialUser = {
username: "",
email: "",
password: "",
password2: "",
name: ""
}
class Register extends React.Component {
constructor(props) {
super(props);
this.state = {
user: initialUser,
registered: ''
};
}
onUsernameChange = event => {
this.setState({ username: event.target.value });
};
onNameChange = event => {
this.setState({ name: event.target.value });
};
onEmailChange = event => {
this.setState({ email: event.target.value });
};
onPasswordChange = event => {
this.setState({ password: event.target.value });
};
onPassword2Change = event => {
this.setState({ password2: event.target.value });
};
isRegistered() {
const { registered } = this.state;
console.log(registered, 'here', this.state)
if (registered) {
this.props.history.push('/login')
}
}
onRegister = () => {
fetch("http://localhost:3000/register", {
method: "post",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: this.state.name,
email: this.state.email,
username: this.state.username,
password: this.state.password,
password2: this.state.password2
})
})
.then(res => res.json())
.then(data => {
console.log(data.isRegistered);
if (data.isRegistered) {
this.setState({registered: true})
this.isRegistered();
}
})
};
render() {
return <div className="login-page">
<div className="form">
<form className="login-form">
<input type="text" placeholder="name" onChange={this.onNameChange} />
<input type="text" placeholder="username" onChange={this.onUsernameChange} />
<input type="text" placeholder="email" onChange={this.onEmailChange} />
<input type="password" placeholder="password" onChange={this.onPasswordChange} />
<input type="password" placeholder="confirm password" onChange={this.onPassword2Change} />
<button className="bluecolor" onClick={this.onRegister}>
Register
</button>
<p className="message">
Have an account? Login
</p>
</form>
</div>
</div>;
}
}
export default withRouter(Register);
And this is the main App.js
import React, { Component } from 'react';
import RegisterFull from "./Components/Register/RegisterFull";
import LoginFull from "./Components/Login/LoginFull";
import HomeFull from "./Components/Home/HomeFull";
import FullContact from "./Components/Contact/FullContact";
import './App.css';
import './Components/flex.css'
import {BrowserRouter as Router, Route} from "react-router-dom";
class App extends Component {
constructor(props) {
super(props);
this.state = {
signedIn: false
}
}
loginUser = () => {
this.setState({signedIn: true})
}
render() {
return (
<Router>
<div>
<Route exact={true} path='/' component={HomeFull}/>
<Route path='/contact' component={FullContact} />
<Route path='/login' component={LoginFull} />
<Route path='/register' component={RegisterFull} />
<Route path='/about' component={HomeFull} />
</div>
</Router>
)
}
}
export default App;
You cannot return Redirect element in render like this by invoking another method in component lifecycles or methods.
You need to wrap your component with withRouter HOC which provides history props.
import {BrowserRouter as Route,, withRouter, Redirect, Link} from 'react-router-dom'
export default withRouter(Register);
and if you want to navigate programmatically :
isRegistered = () => {
const { registered } = this.state;
console.log(registered, 'here', this.state)
if (registered) {
this.props.history.push('/login)
}
}
Some improvements in your code you could make. Here is my suggestion. you don't need to bind anything. You are using latest React. How I know? You are doing onUsernameChange = evnet => {} not onUsernameChange(event){}. Overall #Sakhi Mansoor is right.
import React from "react";
import "./Register.css";
import {
BrowserRouter as Route,
withRouter,
Redirect,
Link
} from "react-router-dom";
const initialUser = {
username: "",
email: "",
password: "",
password2: "",
name: ""
};
class Register extends React.Component {
constructor(props) {
super(props);
this.state = {
user: initialUser,
registered: ""
};
}
handleChange = event => {
this.setState({
user: {
...this.state.user,
[event.target.name]: event.target.value
}
});
};
isRegistered = () => {
const { registered } = this.state;
console.log(registered, "here", this.state);
if (registered) {
this.props.history.push("/login");
}
};
onRegister = event => {
event.preventDefault();
fetch("http://localhost:3000/register", {
method: "post",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(this.state.user)
})
.then(res => res.json())
.then(data => {
console.log(data.isRegistered);
if (data.isRegistered) {
this.setState({ registered: true });
this.isRegistered();
}
});
};
render() {
return (
<div className="login-page">
<div className="form">
<form className="login-form" onSubmit={this.onRegister}>
<input
type="text"
placeholder="name"
name="name"
value={this.state.user.name}
onChange={this.handleChange}
/>
<input
type="text"
placeholder="username"
name="username"
value={this.state.user.username}
onChange={this.handleChange}
/>
<input
type="text"
placeholder="email"
name="email"
value={this.state.user.email}
onChange={this.handleChange}
/>
<input
type="password"
placeholder="password"
name="password"
value={this.state.user.password}
onChange={this.handleChange}
/>
<input
type="password"
placeholder="confirm password"
name="password2"
value={this.state.user.password2}
onChange={this.handleChange}
/>
<button className="bluecolor" type="submit">
Register
</button>
<p className="message">
Have an account? Login
</p>
</form>
</div>
</div>
);
}
}
export default withRouter(Register);
Here is a simple example of how to redirect on a button click.Hope this might help you
import React, { Component } from "react";
import { BrowserRouter,Route,Switch } from 'react-router-dom'
class App extends Component {
render() {
return (
<BrowserRouter>
<Switch>
<Route path="/" exact component={Sample}/>
<Route path="/test" exact render={()=>(<p>Test</p>)}/>
</Switch>
</BrowserRouter>
)
}
}
class Sample extends React.Component {
constructor(props) {
super(props)
this.Click = this.Click.bind(this) // you need to bind the method
}
Click() {
this.props.history.push('/test');
}
render() {
return(
<button onClick={this.Click}>Click</button>
)
}
}
export default App;

Warning: Failed prop type: The prop `todos[0].title` is marked as required in `TodoList`, but its value is `undefined`

I want to add title to my server as you see in the picture enter image description here
its ok to value but its not working with title, title is in my array as can you se in the picture but its still coming this error, Props is defined in other JS file, så any help here
import React from 'react';
import todoInputProps from './TodoInput.props';
const TodoInput = (props) => {
let input;
const handleClick = () => {
props.onAdd(input.value, input.title);
input.title = '';
input.value = '';
input.focus();
};
return (
<div>
<input
type="text"
ref={(currentElement) => { input = currentElement; }}
placeholder="title"
/>
<input
type="text"
ref={(currentElement) => { input = currentElement; }}
placeholder="value"
/>
<button
type="button"
onClick={handleClick}
>
add item
</button>
</div>
);
};
TodoInput.propTypes = todoInputProps;
export default TodoInput;
and
import React from 'react';
import todoItemProps from './TodoItem.props';
import './TodoItem.css';
const TodoItem = (props) => {
const remove = () => {
props.onRemove(props.id);
};
const animateClass = props.animate ? 'added-item' : '';
return (
<li className={`TodoItem-item ${animateClass}`}>
<div className="TodoItem-value">{props.value}</div>
<div className="TodoItem-title">{props.title}</div>
<button
onClick={remove}
>
X
</button>
</li>
);
};
TodoItem.propTypes = todoItemProps;
export default TodoItem;
My todolist
import React from 'react';
import TodoItem from './components/TodoItem';
import todoListProps from './TodoList.props';
import './TodoList.css';
class TodoList extends React.Component {
constructor() {
super();
this.state = {};
this.handleRemove = this.handleRemove.bind(this);
}
componentWillReceiveProps(nextProps) {
nextProps.todos.forEach((todo) => {
const oldValue = this.props.todos.find(oldTodo => oldTodo.id === todo.id);
const isNewTodo = typeof oldValue === 'undefined';
if (isNewTodo) {
this.setState({ addedId: todo.id });
}
});
}
handleRemove(id) {
this.props.onItemRemove(id);
}
render() {
return (
<ul className="TodoList">
{
this.props.todos.map(todoItem => (
<TodoItem
animate
key={todoItem.id}
id={todoItem.id}
value={todoItem.value}
title={todoItem.title}
onRemove={this.handleRemove}
/>
))
}
</ul>
);
}
}
TodoList.propTypes = todoListProps;
export default TodoList;
and my contanier looks like that
import React from 'react';
import TodoInput from './components/TodoInput';
import TodoList from './components/TodoList';
import { getAll, add, remove } from '../../../utils/todo';
import './TodoContainer.css';
class TodoContainer extends React.Component {
constructor() {
super();
this.state = {
todos: [],
};
this.handleRemove = this.handleRemove.bind(this);
this.handleAdd = this.handleAdd.bind(this);
}
componentDidMount() {
getAll().then((todos) => {
this.setState({ todos });
});
}
handleAdd(value, title) {
add(value, title).then((id) => {
this.setState({
todos: this.state.todos.concat([{
id,
value,
title,
}]),
});
});
}
handleRemove(id) {
remove(id).then(() => {
this.setState({
todos: this.state.todos.filter(todoItem => todoItem.id !== id),
});
});
}
render() {
return (
<div className="TodoContainer-wrapper">
<TodoInput onAdd={this.handleAdd} />
<TodoList
todos={this.state.todos}
onItemRemove={this.handleRemove}
/>
</div>
);
}
}
export default TodoContainer;
The problem is that in TodoInput, you try to use one variable input for two React instances. Here's the corrected code of TodoInput:
const TodoInput = (props) => {
let inputTitle, inputValue;
const handleClick = () => {
props.onAdd(inputTitle.value, inputValue.value);
inputTitle.value = '';
inputValue.value = '';
input.focus();
};
return (
<div>
<input
type="text"
ref={(currentElement) => { inputTitle = currentElement; }}
placeholder="title"
/>
<input
type="text"
ref={(currentElement) => { inputValue = currentElement; }}
placeholder="value"
/>
<button
type="button"
onClick={handleClick}
>
add item
</button>
</div>
);
};

Categories

Resources