Set cookie in ReactApp with js-cookie does not recognizes expiration - reactjs

I am trying to set a cookie with an expiration of 10 days in a React app using js-cookie. I followed this document, but when I reload the page, the value of the cookie is undefined always. I expect it to keep the value I set for 10 days.
This is the code where I set the cookie:
handleClick() {
const axios = require('axios');
axios.post('http://127.0.0.1:8000/es/api/login/',
{
username: 'admin#admin.com',
password: 'Cancun10!',
//username: this.state.email,
//password: this.state.password.password,
},
)
.then(function (response) {
Cookies.set('x-xsrf-token', response.token, {expires: 10});
console.log(response);
})
.catch(function (error) {
console.log(error);
})
}
And this is the code where I get the value of the cookie:
class App extends Component {
render() {
var csrfCookie = Cookies.get('x-xsrf-token')
if(csrfCookie === 'undefined'){
return (
<div className="App">
<LoginModal />
</div>
);
} else {
return (
<div className="App">
<Albums />
</div>
)
}
}
}
export default App;
I expect the if to send to LoginModal the first time, but then to send to Albums every time after, for 10 days.

I found the mistake. The cookie is ok, but I was comparing the value of the cookie against 'undefined', but I have to compare it against undefined. As soon as I changed the condition like this: if(csrfCookie === undefined), everything worked.

Related

React - PayPal Button fires without checking conditions

I'm using react-paypal-express-checkout
I've to options: Cash and PayPal.
Cash working fine and checks all conditions.
But bcs PayPal is a seperate component in my CartScreen component it opens and don't check a single if conditions and opens the PayPal window
The CashButton comes with function "cashTranSuccess" it's the same function as "TranSuccess"
just without the paymentID bcs it's only needed for react-paypal-express-checkout
So what I'm looking for is, to check all TranSuccess() conditions before open the PayPal window.
PayPalButton.js
import React from 'react';
import PaypalExpressBtn from 'react-paypal-express-checkout';
export default class PayPalButton extends React.Component {
render() {
const onSuccess = (payment) => {
// Congratulation, it came here means everything's fine!
console.log('The payment was succeeded!', payment);
// You can bind the "payment" object's value to your state or props or whatever here, please see below for sample returned data
this.props.tranSuccess(payment);
};
const onCancel = (data) => {
// User pressed "cancel" or close Paypal's popup!
console.log('The payment was cancelled!', data);
// You can bind the "data" object's value to your state or props or whatever here, please see below for sample returned data
};
const onError = (err) => {
// The main Paypal's script cannot be loaded or somethings block the loading of that script!
console.log('Error!', err);
// Because the Paypal's main script is loaded asynchronously from "https://www.paypalobjects.com/api/checkout.js"
// => sometimes it may take about 0.5 second for everything to get set, or for the button to appear
};
let env = 'sandbox'; // you can set here to 'production' for production
let currency = 'EUR'; // or you can set this value from your props or state
let carttotal = this.props.carttotal; // same a s above, this is the total amount (based on currency) to be paid by using Paypal express checkout
// Document on Paypal's currency code: https://developer.paypal.com/docs/classic/api/currency_codes/
const client = {
sandbox:
'',
production: 'YOUR-PRODUCTION-APP-ID',
};
// In order to get production's app-ID, you will have to send your app to Paypal for approval first
// For sandbox app-ID (after logging into your developer account, please locate the "REST API apps" section, click "Create App"):
// => https://developer.paypal.com/docs/classic/lifecycle/sb_credentials/
// For production app-ID:
// => https://developer.paypal.com/docs/classic/lifecycle/goingLive/
// NB. You can also have many Paypal express checkout buttons on page, just pass in the correct amount and they will work!
// Style Options: https://developer.paypal.com/docs/checkout/standard/customize/buttons-style-guide/ ; https://wise.com/gb/blog/custom-paypal-button
let style = {
size: 'medium',
color: 'gold',
label: 'pay',
tagline: false,
};
return (
<PaypalExpressBtn
env={env}
client={client}
currency={currency}
total={carttotal}
onError={onError}
shipping={1}
onSuccess={onSuccess}
onCancel={onCancel}
style={style}
/>
);
}
}
CartScreen
const tranSuccess = async (payment) => {
const { paymentID } = payment;
// Check time, min amoint, for delivery add delivery fees
if (timeValidation === true) {
if (sliderDeliveryValue === 'delivery') {
if (carttotal > settings[0]?.minDeliveryAmount) {
await axios.post(
'/api/payment',
{ cartItems, paymentID, time, sliderDeliveryValue, carttotal },
{
headers: { Authorization: token },
}
);
cartItems.map((remove) => {
dispatch(deleteFromCart(remove));
});
//console.log(cartItems.length);
toast.success(
'Order successful',
{
position: toast.POSITION.TOP_RIGHT,
}
);
} else {
toast.error(
`Min amount${settings[0]?.minDeliveryAmount}€`,
{
position: toast.POSITION.TOP_RIGHT,
}
);
}
} else if (sliderDeliveryValue === 'pickup') {
if (carttotal > 2) {
await axios.post(
'/api/payment',
{ cartItems, paymentID, time, sliderDeliveryValue, carttotal },
{
headers: { Authorization: token },
}
);
cartItems.map((remove) => {
dispatch(deleteFromCart(remove));
});
//console.log(cartItems.length);
toast.success(
'Order successful',
{
position: toast.POSITION.TOP_RIGHT,
}
);
} else {
toast.error(`Min amount 2.00€`, {
position: toast.POSITION.TOP_RIGHT,
});
}
} else {
toast.error('Choose delivery method', {
position: toast.POSITION.TOP_RIGHT,
});
}
} else {
toast.error('closed', {
position: toast.POSITION.TOP_RIGHT,
});
}
};
<PayPalButton
carttotal={carttotal}
tranSuccess={tranSuccess}
/>
<div onClick={cashTranSuccess}>
<CashButton />
</div>
Consider using the official #paypal/react-paypal-js
An example of validation using onInit and onClick functions and the actions.enable/disable callbacks or returning a promise (actions.resolve/reject) can be found in the developer documentation. Adapt this to check whatever condition you need.

Fetching video array from cloudinary on React app

I have React web app with video hosting by cloudinary. I want to know the methods for pulling a random video from cloudinary library or making array? Database used is mongodb.
Here is code from VideoPlayer Component. I get React Error 152 when I try to run.
export default class VideoPlayer extends React.Component {
state = {
randomId: ''
};
componentDidMount() {
this.randomId();
}
randomId = () => {
axios
.get(inDev ? devAPI.concat("v2/getRandomId") : baseAPI.concat("v2/getRandomId"))
.then(data => this.setState({ randomId: data }))
.catch(err => {
console.log(err);
return null;
});
};
render() {
return(
<div>
{this.state.randomId.length === 0 ? (
<div>Loading...</div>
) : (
<div>this.state.randomId</div>
)}
</div>
)
}
}
Here is API
router.get("/v2/getRandomId", (req, res) => {
cloudinary.search.max_results(1).execute().then(result=>{
return res.json({
success: true,
data: result.resources
});
});
});
Thanks
I ended up creating a random number generator then assigning product of that variable to the Index value of video array carousel to shuffle videos on every page load. Random number generator was placed in componentWillMount Method to occur on every page load.
Thank you for all the help.

How to handle response.item is undefined?

I am getting the error below although I bound getNowPlaying, can someone help if I am missing something in my code? Is the way I tried to import SpotifyWebApi wrong?
Here is the code that causes problems:
import React, { Component } from 'react';
import './App.css';
import SpotifyWebApi from 'spotify-web-api-js';
const spotifyApi = new SpotifyWebApi();
class App extends Component {
constructor(props){
super(props);
const params = this.getHashParams();
const token = params.access_token;
if (token) {
spotifyApi.setAccessToken(token);
}
this.state = {
loggedIn: token ? true : false,
nowPlaying: { name: 'Not Checked', albumArt: '' }
}
this.getNowPlaying=this.getNowPlaying.bind(this);
}
getNowPlaying(){
spotifyApi.getMyCurrentPlaybackState()
.then((response) => {
this.setState({
nowPlaying: {
name: response.item.name,
albumArt: response.item.album.images[0].url
}
});
})
}
render() {
return (
<div className="App">
<a href='http://localhost:8888' > Login to Spotify </a>
<div>
Now Playing: { this.state.nowPlaying.name }
</div>
</div>
);
}
}
export default App;
According to Spotify docs
Response A successful request will return a 200 OK response code with
a json payload that contains information about the currently playing
track or episode and its context (see below). The information returned
is for the last known state, which means an inactive device could be
returned if it was the last one to execute playback.
When no available devices are found, the request will return a 200 OK
response but with no data populated.
When no track is currently playing, the request will return a 204 NO
CONTENT response with no payload.
If private session is enabled the response will be a 204 NO CONTENT
with an empty payload.
That means that even if your request is successful (200 OK), the response can be empty so you need to do defensive programming by checking if the response is not empty
I am not sure what is the exact object the request returns but you can do something like this
spotifyApi.getMyCurrentPlaybackState()
.then((response) => {
this.setState({
nowPlaying: {
name: response && response.item && response.item.name,
albumArt: response && response.item && response.item.album && response.item.album.images.length > 0 && response.item.album.images[0].url
}
});
})
The problem here is that the properties you need are deeply nested, and also you need to check if the images array length is greater than 0, so probably a better approach is to store all the response object in the state and then checking it at render time.
if that's not possible you can use optional chaining but for that you will have to use a babel plugin https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining
And then you can do
spotifyApi.getMyCurrentPlaybackState()
.then((response) => {
this.setState({
nowPlaying: {
name: response?.item?.name,
albumArt: response?.item?.album?.images[0].url
}
});
})

I am getting the error message Warning: Can't perform a React state update on an unmounted component

I am getting the error message
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.in Login (created by Context.Consumer`)
I am have tried the most common fix for that issue but it didn't work. The fix where you use _isMounted = false; componentDidMount() { this._isMounted = true;} if (this._isMounted) {this.setState({ data: data});}
I am also using Context.
SessionContex.js
import React, { Component, createContext } from "react";
export const SessionContext = createContext();
class SessionContextProvider extends Component {
_isMounted = false;
state = {
is_logged_in: false,
personid: " ",
firstname: " ",
lastname: " "
};
loggedIn = (loginvalue, personid, firstname, lastname) => {
this.setState({
is_logged_in: loginvalue,
personid: personid,
firstname: firstname,
lastname: lastname
});
};
loggedOut = () => {
this.setState({
is_logged_in: false,
personid: " ",
firstname: " ",
lastname: " "
});
};
componentDidMount = () => {
this._isMounted = true;
const login = localStorage.getItem("is_logged");
const id = localStorage.getItem("personid");
const firstname = localStorage.getItem("firtname");
const lastname = localStorage.getItem("lastname");
console.log(login);
if (this._isMounted) {
this.setState({
is_logged_in: login,
personid: id,
firstname: firstname,
lastname: lastname
});
}
};
componentWillUnmount() {
this._isMounted = false;
}
render() {
return (
<SessionContext.Provider
value={{
...this.state,
loggedIn: this.loggedIn,
loggedOut: this.loggedOut
}}
>
{this.props.children}
</SessionContext.Provider>
);
}
}
export default SessionContextProvider;
Login.jsx
import React, { Component } from "react";
import { SessionContext } from "../context/SessionContext";
import "../Stylesheets/Login.css";
import "..//Stylesheets/global.css";
import { Redirect } from "react-router-dom";
class Login extends Component {
_isMounted = false;
static contextType = SessionContext;
state = {
password: " ",
email: " ",
couldNotfindLogin: true,
redirect: false
};
handleChange = e => {
this.setState({
[e.target.name]: e.target.value,
[e.target.name]: e.target.value
});
};
handleSubmit = async e => {
e.preventDefault();
const data = this.state;
console.log(data);
const response = await fetch("http://localhost:3080/users/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
const reply = await response;
if (reply.status === 200) {
const userData = await response.json();
this.context.loggedIn(
userData.isValid,
userData.personid,
userData.firstname,
userData.lastname
);
localStorage.setItem("is_logged", userData.isValid);
localStorage.setItem("personid", userData.personid);
localStorage.setItem("firstname", userData.firstname);
localStorage.setItem("lastname", userData.lastname);
this.setState({
couldNotfindLogin: true,
redirect: true
});
}
if (reply.status !== 200) {
this.context.loggedIn(false);
console.log(this.context);
}
this.setState({
couldNotfindLogin: false
});
};
componentWillUnmount() {
this.mounted = false;
}
render() {
let { couldNotfindLogin } = this.state;
if (this.state.redirect === true) {
return <Redirect to="/" />;
}
return (
<>
<section className="container">
<div className="row">
<div className="col-sm-12 col-md-12 col-lg-12 login-section">
<div className="form login-box">
<form className="form-login Login" onSubmit={this.handleSubmit}>
<label htmlFor="Email">
<p className="login-header">
Login to see your past, present, and future self.
</p>
<input
className="login-input"
id="Email"
type="text"
name="email"
onChange={this.handleChange}
placeholder="Email Address"
required
/>
{!couldNotfindLogin ? (
<p className="FindYou">We could not find your account </p>
) : (
" "
)}
</label>
<label htmlFor="Password">
<input
className="login-input"
id="Password"
type="password"
name="password"
onChange={this.handleChange}
placeholder="Password"
required
/>
</label>
<button className="login-button" type="submit">
Login
</button>
</form>
</div>
</div>
</div>
</section>
</>
);
}
}
I found a few mistakes that are holding you back. I'll try to brief as to not make this a long-winded answer:
Allow the Provider to handle all things related to high-level state and localStorage. Only use local state that's revelant to the component. Also, since setState() is asynchronous, avoid setting it immediately following another asynchronous function(s). While you do have an _isMounted class property, it isn't being checked against when the async function (fetch request) resolves, therefore if you're redirecting the user to another route while React attempts to update the component state, then you'll get these warnings as described above. Put simply, utilize the _isMounted in the async function right before using setState or simply avoid using setState (see example below).
The handleChange class field only needs a single [e.target.name]: e.target.value statement. Having two is unnecessary. You can use object destructuring to simplify this down to: [name]: value (see example below).
Any component provided to a Route has access to some route props. Among the props is a history object that contains several methods -- among them is a push method. You can use this push method to redirect a user to another url: this.props.history.push("url"). Again this is provided, by default, to a component that resides in a react-router-dom Route.
async/await will only work on promises. Therefore, you'll want to await the initial fetch response and then await the fetch response.json() promise. The first promise, returns a Stream object, while the second promise returns a JSON object (this is by design, other libraries, like axios, skip this second promise). Therefore, const reply = await response; expression isn't necessary as it's not waiting for promise a resolve, but instead it's just setting the response's Stream object to a reply variable.
Lastly, only use let for variables if you plan on updating or mutating this variable dynamically within the same execution cycle; otherwise, just use const. This becomes especially important because state and props should always be immutable for React to know when or if they have been updated (via another component or by setState). Simply put, avoid using let for state/prop expressions like: let { password } = this.state.
Working example (I'm mimicking the fetch response promise, but you can play around with it by checking out the src/api/index.js file -- for example you can trigger an error response by submitting a password as invalid):

conditional rendering at empty response of API in react js

I am building a little react js application where users can select a few filters and get response accordingly. For some values selected by users, nothing is found from database and I want to show "nothing found" message.
I tried using if & else conditional operators which is not producing results. Below is the code.
.then(res => {
if(!res.data.length){
return(
<div>
<h1>nothing found.</h1>
</div>
)
}
else{
this.setState({ data: res.data,urlList:[] })
console.log(this.state)
}
})
Now If I do this
.then(res => {
if(!res.data.length){
console.log('nothing found')
}
else{
this.setState({ data: res.data,urlList:[] })
console.log(this.state)
}
})
I am getting a response on console. What I am doing wrong ?
declare a new state variable like
constructor(props){
super(props);
this.state = {
noData: ''
}
}
And here
.then(res => {
if(!res.data.length){
this.setState({noData: 'nothing found'});
console.log('nothing found')
}
else{
this.setState({ data: res.data,urlList:[], noData: '' })
console.log(this.state)
}
})
And in render just display this.state.noData
render(){
return(
<div>
<h1>{this.state.noData}</h1>
</div>
)
}
Log out the res.data object for a case when nothing is found. It may not be an empty array as your code assumes, but might contain some message to the effect that nothing on the database matches your query. You need to check for this rather than simply !res.data.

Resources