can't seem to get this array to work with splice - arrays

I am trying to get a new fortune to get included into my array when someone submits a fortune but I can't get it to work now matter what im trying. Do I like it to the other file where someones submit their fortune, or am I messing up somewhere else?
import React from "react";
import {Link} from "react-router-dom"
import AddFortune from "./add-fortune";
class Fortune extends React.Component {
constructor(props) {
super(props);
this.state = {
fortunes: [
"An exciting opporunity lies ahead",
"A long time friend will brirng wise advice in the coming week",
"You will find great fortunes in unexpected places",
"Never give up... Unless you want to thats cool too",
"111",
"222",
"333",
"444",
"Maybe a nap is what you need",
"Don't Text Your EX!"
],
array.push('
fortune: "" ');
array.splice(array.length, 0, '{fortune:""}');
array[array.length] = fortune: "";
}
}
componentDidMount() {
this.getFortune();
}
getFortune = () => {
let rand = Math.floor(Math.random() * (this.state.fortunes.length) + 0)
console.log(rand);
this.setState({
fortune: this.state.fortunes[rand]
})
}
render() {
return (
<body>
<div className="home-buttons-wrapper">
<button onClick={this.getFortune}>Your Fortune</button>
</div>
<h5>{this.state.fortune}</h5>
</body>
)
}
}
console.log('getFortune');
export default Fortune;
What im trying to get to be added to the fortunes file
import React, { Component } from 'react'
export default class AddFortune extends Component {
constructor(props) {
super(props)
this.state = {
nameInput: "",
loading: false,
error: false
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.value })
}
handleSubmit(event) {
event.preventDefault()
this.setState({
loading: true,
error: false
})
fetch("https://backend-edwin.herokuapp.com/item/add", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
name: this.state.nameInput
})
})
.then(response => response.json())
.then(data => {
if (data.id) {
this.props.history.push("/fortune")
}
})
.catch(error => {
console.log("Error adding fortune ", error)
this.setState({
loading: false,
error: true
})
})
}
render() {
return (
<div className='add-item-wrapper'>
<h2>Add Fortune</h2>
<form onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="fortune"
name="nameInput"
value={this.state.nameInput}
onChange={this.handleChange}
/>
<button type="submit" disabled={this.state.loading}>Add Fortune</button>
</form>
{this.state.loading ? <div className="loading">Submitting...</div> : null}
{this.state.error ? <div className="error">An error occured... Please try again later.</div> : null}
</div>
)
}
}

Here is a method to get a random fortune from a list of fortunes.
import React from "react";
class Fortune extends React.Component {
constructor(props) {
super(props);
this.state = {
fortunes: [],
fortune: '',
loading: true,
error: false
}
}
componentDidMount() {
fetch("https://backend-edwin.herokuapp.com/item/", {
method: "GET",
headers: { "content-type": "application/json" },
})
.then(response => response.json())
.then(data => {
this.setState({
loading: false,
fortunes: data, //check how the data is coming from api and add the variable here if fortunes list `if data.fortunes` then add data.fortunes here
error: false
}, this.getFortune)
})
.catch(error => {
console.log("Error fetching fortune ", error)
this.setState({
loading: false,
error: true
})
})
}
getFortune = () => {
let rand = Math.floor(Math.random() * (this.state.fortunes.length - 1) + 0)
console.log(rand);
this.setState({
fortune: this.state.fortunes[rand]
})
}
render() {
if(this.state.loading) {
return (<div>Loading .....</div>)
}
if(this.state.error) {
return (<div>Error occurred in API</div>)
}
return (
<div>
<div className="home-buttons-wrapper">
<button onClick={this.getFortune}>Your Fortune</button>
</div>
<h5>{this.state.fortune}</h5>
</div>
)
}
}
export default Fortune

Related

Error: Objects are not valid as a React child. If you meant to render a collection of children, use an array instead using Reactjs

How to solve this issue,Error: Objects are not valid as a React child (found: object with keys {cashback, image, logo, store_branches, store_id, store_name, store_summary, store_url}). If you meant to render a collection of children, use an array instead. I need **stores_list ** object data could you please help me.
My Component:
import React, { Component } from 'react';
import { Grid} from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import OwlCarousel from 'react-owl-carousel';
export default class ApiData extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true
};
}
async componentDidMount() {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'React POST Request Example' })
};
const url = "https://localhost/api/v4/web/home";
fetch(url,requestOptions)
.then((response) => response.json())
.then((json) => {
this.setState({ data: json.sections.collections});
})
.catch((error) => console.error(error))
.finally(() => {
this.setState({ isLoading: false });
});
}
render() {
if (!this.state.data) {
return null;
}
var i=0;
var s;
if (i<this.state.data.length){
return s=this.state.data[i]["stores_list"];
i++
}
console.log(s)
return (
<Grid className='slider-three'>
</Grid>
);
}
};
my JSON:
collections": [
{
"home_offer_id": 71,
"stores_list": [
{
"cashback": "200",
"image": "https://dl8mjowvdz1rh.cloudfront.net/stores/Nara_Pan_Asis_Detail_1620125271937.jpeg",
"logo": "https://dl8mjowvdz1rh.cloudfront.net/stores/Nara_Pan_Asia_Logo_1620125267963.jpeg",
"store_branches": [
{
"store_city": "Dubai",
"store_location": "JLT"
}
],
"store_id": 120,
"store_name": "NARA Pan Asian",
"store_summary": "JLT, Brunch, Asian, Japanese, Thai, Chinese",
"store_url": "/store/nara-pan-asian/120"
}
]
}
]
}
You get that error when you try to return an {Object} instead of a [Array].
Reading your code it seems its likely coming from return s=this.state.data[i]["stores_list"];. Try using .map method to return an array of the results.
What you want to try to return should look like [{<Object>},{<Object>},{<Object>}]
import React, { Component } from 'react';
import { Grid} from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import OwlCarousel from 'react-owl-carousel';
export default class ApiData extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true
};
}
async componentDidMount() {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'React POST Request Example' })
};
const url = "https://localhost/api/v4/web/home";
fetch(url,requestOptions)
.then((response) => response.json())
.then((json) => {
this.setState({ data: json.sections.collections});
})
.catch((error) => console.error(error))
.finally(() => {
this.setState({ isLoading: false });
});
}
render() {
if (!this.state.data){
return null;
}
const storesList = []
for (let index = 0; index < this.state.data.length; index++) {
const element = this.state.data[index];
storesList.push(element);
}
return (
<Grid className='slider-three'></Grid>
)
}
}
Try using the Array Instance Method .map() which expects a callback function. That callback function (store)=>store['stores_list'] is applied to each item and returns a brand new array for you in the storesList constant which is now an Array that looks like [{this.data[0]['stores_list']}, {this.data[1]['stores_list']}, {this.data[2]['stores_list']}, ..., {this.data[i]['stores_list']}] for i stores such that i === this.data.length.
Hopefully this helps

Username state gets undefined / null after a few minutes in JWT authentication React Django

I am making a React application with the backend of the Django REST framework. Everything works fine except when retrieving the username. Retrieving the username is no problem but keeping it for a time is a problem. I'm going to explain using comments now in the code;
import React, { Component } from 'react';
import Nav from './Components/Navbar';
import LoginForm from './Components/LoginForm';
import SignupForm from './Components/SignupForm';
import Layout from './Containers/Layout';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
displayed_form: '',
logged_in: localStorage.getItem('token') ? true : false,
username: '', // username state
error: null
};
}
componentDidMount() {
if (this.state.logged_in) {
fetch('http://localhost:8000/core/current_user/', { // fetch is used to get current user
headers: {
Authorization: `JWT ${localStorage.getItem('token')}`
}
})
.then(res => res.json())
.then(json => {
this.setState({ username: json.username }); // set the state
});
}
}
handle_login = (e, data) => {
e.preventDefault();
fetch('http://localhost:8000/token-auth/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(json => {
try {
localStorage.setItem('token', json.token);
this.setState({
logged_in: true,
displayed_form: '',
username: json.user.username,
error: '',
})
} catch (error) {
this.setState({error: "We Couldn't log you in, maybe theres a typo in the data you entered"})
this.handle_logout()
}
});
};
handle_signup = (e, data) => {
e.preventDefault();
fetch('http://localhost:8000/core/users/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(json => {
try {
localStorage.setItem('token', json.token);
this.setState({
logged_in: true,
displayed_form: '',
username: json.username,
})
if (this.state.username == 'A user with that username already exists.') {
this.setState({logged_in: false, username: '', error: 'Yikes, we could not create your account, you have used an existing username. Try again please...'})
this.handle_logout()
}
} catch (error) {
alert("Error")
}
});
};
handle_logout = () => {
localStorage.removeItem('token');
this.setState({ logged_in: false, username: '' });
};
display_form = form => {
this.setState({
displayed_form: form
});
};
render() {
let form;
switch (this.state.displayed_form) {
case 'login':
form = <LoginForm handle_login={this.handle_login} />;
break;
case 'signup':
form = <SignupForm handle_signup={this.handle_signup} />;
break;
default:
{
this.state.logged_in ?
form = null
:
form = <LoginForm handle_login={this.handle_login} />
}
}
return (
<div className="App">
<Nav
logged_in={this.state.logged_in}
display_form={this.display_form}
handle_logout={this.handle_logout}
/>
{form}
<h3>
{
this.state.logged_in && this.state.username !== undefined ?
<Layout username={this.state.username} />
: this.state.error ?
<p className="error">{this.state.error}</p>
: this.state.username == undefined ?
<div>
<p className="error" style={{maxWidth: 650, minHeight: 30, padding: 20}}>You exceeded the time being logged in, we take your account safety seriously. So please logout now and login again...</p>
{this.handle_logout}
</div>
:
<p></p>
}
</h3>
</div>
);
}
}
export default App;
If you read through everything, I have said that this.state.logged_in && this.state.username !== undefined ? show the layout component.
In that component, I have put an h1 with {this.state.username}.
The username gets shown but it becomes null/undefined after about 5 minutes. Even though, in the backend Django REST API, the current username can be seen.
I am very confused about why this is happening.
Update
I fixed this by using local storage to set a username and get the username. But, I want to know if this is safe.

Fetch Array data from API ReactJS

i try fetch array data from a API with token, the problem is i fail to render/bind to display,every time debug will show error message like this. Please guide me, im new to react, this is my 1st app.
how to bind array to myadapater?
error
here my code:
import React, { Component } from "react";
import ReactDOM from "react-dom";
const url = " "; //api customer
const token = " "; //token
class Client extends Component {
constructor(props) {
super(props);
this.state = {
error: undefined,
isLoaded: false,
items: []
};
this.getData = this.getData.bind(this);
}
componentDidMount() {
this.getData();
}
getData() {
return fetch(url, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + token
}
})
.then((res) => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
<p>data {items}</p>
{items.map((items) => (
<div>{items.name}</div>
))}
</div>
);
}
}
}
export default Client;
There is only one real issue.
The use of {items} in the render method. If you want to display the actual JSON try {JSON.stringify(items)} instead.
Besides that i would also not use the same name in the map. So instead of items for the map function i would use item since you are dealing with one of the items.
<div>
<p>data {JSON.stringify(items)}</p>
{items.map((item) => (
<div>{item.name}</div>
))}
</div>
Additionally, since you only use getData in the componentDidMount you do not need to bind it in the constructor (that is required if you intent to pass that function to other component/functions outside of the current one)
And you also do not need to return anything for the getData function since you handle the result in the then handlers.
So,
class Client extends Component {
constructor(props) {
super(props);
this.state = {
error: undefined,
isLoaded: false,
items: []
};
}
componentDidMount() {
this.getData();
}
getData() {
fetch(url, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + token
}
})
.then((res) => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
<p>data {JSON.stringify(items)}</p>
{items.map((item) => (
<div>{item.name}</div>
))}
</div>
);
}
}
}

How do I properly call multiple functions in componentDidMount?

I am trying to call two different functions to display data on my page and one is working (getUserscards) and the second one is not (getUserInfo). I saw that you can put two different function calls for the data in componentDidMount and I have tried doing it several ways but the data for the email and names is not showing up. I will include the code from my profilepage where the componentDidMount is and from my api page where the function is made.
Here is my code in profilepage. js:
import React from 'react'
import { getUsersCards, getUsersInfo } from '../Api'
class ProfilePage extends React.Component {
constructor () {
super()
this.state = {
token: window.localStorage.getItem('login_auth_token'),
username: localStorage.getItem('login_username') || '',
email: '',
first_name: '',
last_name: '',
cards: []
}
}
componentDidMount () {
if (this.state.token) {
getUsersCards(this.state.token)
.then(cards => this.setState({ cards: cards }))
}
getUsersInfo(this.state.email, this.state.first_name, this.state.last_name)
.then(data => this.setState({ data: data }))
}
componentDidUpdate (prevProps, prevState) {
if (this.state.token && this.state.token !== prevState.token) {
getUsersCards(this.state.token).then(cards => this.setState({ cards: cards }))
}
}
render () {
return (
<div>
<div className='container2'>
<div>
<p>Username: {this.state.username}</p>
</div>
<div>
Email: {this.state.email}
</div>
<div>
<p>Name: {this.state.first_name}{this.state.last_name}</p>
</div>
</div>
<div>
{this.state.cards.map(card => <p className='container' key={card.id}> Title: {card.card_name} <br /> Card: {card.card_text}</p>)}
</div>
</div>
)
}
}
export default ProfilePage
And here is the function from my api.js page:
export function getUsersInfo (token) {
return request.get('/users/info', {
headers: {
Authorization: `Token ${token}`
}
}).then(res => {
console.log(res.data)
return res.data
})
}
The thing is, when you call this.setState({ data: data }), in your state MUST HAVE a key data.
Maybe change into this may help
this.setState({ email: data.email, first_name: data.first_name, last_name: data.last_name })
Just need the exactly key to work
the problem is likely here,
export function getUsersInfo (token) {
return request.get('/users/info', {
headers: {
Authorization: `Token ${token}`
}
}).then(res => {
console.log(res.data)
return res.data //!! note
})
}
You are returning raw data from the server when are you parsing it to json, YOu Must parse it somehow to make is object so you can use.

Reactjs Dropzone and Laravel 5.6

I'm trying to create a way to attach files from Reactjs Dropzone plugin to an axios POST request.
Currently, my module is doing the following ajax request:
submitPost() {
const formData = new FormData;
const err = this.validate();
if( !err ) {
this.setState({buttonText: 'Posting...'});
axios.post('/user/post/create/', {
content: this.state.post_content,
images: this.state.images,
headers: {
'Content-Type': 'multipart/form-data'
},
})
.then(response => {
console.log(response);
this.setState({buttonText: 'Success'});
setTimeout(
function() {
this.setState({
buttonText: 'Post',
post_content: '',
images: []
});
$('#post_content').val('');
}.bind(this), 1000
);
}).catch(error => {
console.log(error.response);
this.setState({buttonText: 'Error'});
setTimeout(
function() {
this.setState({buttonText: 'Post'});
}.bind(this), 1000
);
});
} else {
this.setState({buttonText: 'Error'});
setTimeout(
function() {
this.setState({buttonText: 'Post'});
}.bind(this), 1000
);
}
}
And the following states are defined:
constructor(props){
super(props);
this.state= {
progressValue: '0',
progressText: '0%',
buttonText: 'Post',
post_content: '',
images: []
}
}
And here is the Uploader Module i've written using Reactjs Dropzone:
import React, { Component } from 'react';
import Dropzone from 'react-dropzone'
import $ from "jquery";
export class Uploader extends Component {
constructor(props){
super(props);
this.state= {
images: this.props.images
}
}
onDrop(files) {
this.setState({
images: files
});
console.log(files);
this.props.handleImageUpload(files);
}
render() {
return (
<div className="uploader">
<div className="previews">
{this.state.images.map((file) =>
<div
className="preview"
key={file.preview}>
<img src={file.preview} />
</div>
)}
</div>
<Dropzone onDrop={this.onDrop.bind(this)}>
<p>Try dropping some files here, or click to select files to upload.</p>
</Dropzone>
</div>
);
}
}
Any help would be appreciated, I'm currently trying to upload the files from the Images state which comes through as an array, but comes through in this format:
[{"preview":"blob:http://outist.local/3c3fc96b-b89d-41c8-8835-3309be8ac430"},{"preview":"blob:http://outist.local/6cf9aa40-0538-4cef-affe-58951afef2eb"},{"preview":"blob:http://outist.local/4631977b-1301-498d-b4e8-611f9a57b6bb"},{"preview":"blob:http://outist.local/1650a49c-2eed-408c-a035-473cade2bfa6"}]

Resources