I have three different components that within them are using a component called StripeCheckout and one of the properties of StripeCheckout is description which I currently have as a string:
import React, { Component } from "react";
import StripeCheckout from "react-stripe-checkout";
import { connect } from "react-redux";
import * as actions from "../actions";
class SunnySampler extends Component {
render() {
return (
<div>
<StripeCheckout
name='Microurb Farms'
amount={this.props.amount}
description='Sunny Sampler Box'
shippingAddress
billingAddress={false}
zipCode={true}
token={(token, amount) =>
this.props.handleToken(token, this.props.amount)
}
stripeKey={process.env.REACT_APP_STRIPE_KEY}
/>
</div>
);
}
}
export default connect(null, actions)(SunnySampler);
SunnySampler is just one of the three components making use of StripeCheckout. Each has its own amount property dynamically coded and passed down to the express api and yet I cannot seem to pass down the description property successfully.
The challenge also is that each description property is different depending on which component was selected.
So I was able to pass in the amount dynamically here:
const tiers = [
{
title: "Half pound boxes",
price: "10",
description: [
"Sunflower Shoots",
"Pea Shoots",
"Radish Shoots",
"Broccoli Shoots",
],
buttonText: <HalfPound amount={1000} />,
buttonVariant: "outlined",
},
{
title: "Grasses",
subheader: "Tray",
price: "15",
description: ["Wheatgrass", "Barleygrass"],
buttonText: <Grasses amount={1500} />,
buttonVariant: "contained",
},
{
title: "Sunny Sampler Box",
price: "20",
description: [
"6oz Sunflower",
"2oz Broccoli",
"3oz Sweet Pea",
"2oz Radish",
],
buttonText: <SunnySampler amount={2000} />,
buttonVariant: "outlined",
},
];
this is inside of Dashboard.js, then in my action creator I pass it in like so:
export const handleToken = (token, amount) => async (dispatch) => {
const res = await axios.post("/api/stripe", { token, amount });
dispatch({ type: FETCH_USER, payload: res.data });
};
Inside each of those payment type of components it looks like so:
import React, { Component } from "react";
import StripeCheckout from "react-stripe-checkout";
import { connect } from "react-redux";
import * as actions from "../actions";
class SunnySampler extends Component {
render() {
return (
<div>
<StripeCheckout
name='Microurb Farms'
amount={this.props.amount}
description='Sunny Sampler Box'
shippingAddress
billingAddress={false}
zipCode={true}
token={(token, amount) =>
this.props.handleToken(token, this.props.amount)
}
stripeKey={process.env.REACT_APP_STRIPE_KEY}
/>
</div>
);
}
}
export default connect(null, actions)(SunnySampler);
and finally my backend api:
const keys = require("../config/keys");
const stripe = require("stripe")(keys.stripeSecretKey);
module.exports = (app) => {
app.post("/api/stripe", async (req, res) => {
const { amount, token } = req.body;
// const description = req.body.data.description;
const charge = await stripe.charges.create({
amount: amount,
currency: "usd",
source: token.id,
});
console.log(charge);
});
};
I tried taking the same approach I took to the amount property with the description property and variations of it and I am still getting undefined.
Originally, inside the action creator I had passed in description to it and then inside the handleToken I had passed in this.props.description and then inside the api route on the backend I had req.body.description which should have worked, but I got undefined.
When I console log req.body I see in the data structure description: null, despite having passed a string into the description property inside of StripeCheckout component. I cannot explain why that is.
Related
I am making a NextJS React application and trying to fetch data from my server using this line:
let data = await fetch('/api/getAllAlumniInfoList').then(res => res.json())
When I run the server using next dev, everything works fine. But when I try to build the application for production using next build I get this error:
(node:173544) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
node:internal/deps/undici/undici:5491
throw new TypeError("Failed to parse URL from " + input, { cause: err });
^
TypeError: Failed to parse URL from /api/getAllAlumniInfoList
at new Request (node:internal/deps/undici/undici:5491:19)
at Agent.fetch2 (node:internal/deps/undici/undici:6288:25)
... 4 lines matching cause stack trace ...
at Wc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
at Zc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
at Z (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
at Zc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:481) {
[cause]: TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:393:5)
at URL.onParseError (node:internal/url:564:9)
at new URL (node:internal/url:644:5)
at new Request (node:internal/deps/undici/undici:5489:25)
at Agent.fetch2 (node:internal/deps/undici/undici:6288:25)
at Object.fetch (node:internal/deps/undici/undici:7125:20)
at fetch (node:internal/process/pre_execution:214:25)
at onSearch (/app/goatconnect/goatconnect/.next/server/pages/coach/alumniView.js:75:30)
at PlayersView (/app/goatconnect/goatconnect/.next/server/pages/coach/alumniView.js:103:9)
at Wc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44) {
input: '/api/getAllAlumniInfoList',
code: 'ERR_INVALID_URL'
}
}
Another strange thing about this error is I have different pages with the same exact structure using the same logic that work fine and the compiler does not complain about. I am not sure what could be causing this API route to not be recognized correctly.
I have tried to use the NextJS provided hook useSWR which works in a lot of other instances but this specific use case is for a database search so using a hook causes a infinite loop when the page is updated with the results of the API call.
useSWR is a good option but for fetch i would recommend using unfecth as a fetcher for useSWR. Worked without issues for me.
import fetch from 'unfetch'
import useSWR from 'swr'
function YourComponent() {
const { data, error } = useSWR('/api/getAllAlumniInfoList', fetch)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
An update with search input, useSWR and no infinite loop:
import { ChangeEvent, useCallback, useState } from "react";
import styles from "../styles/Home.module.css";
import fetch from "unfetch";
import useSWR from "swr";
import { debounce } from "lodash";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
export default function Home() {
const [value, setValue] = useState<string>("");
const { data = [], error } = useSWR(
value ? `/api/user/${value}` : null,
fetcher,
{
fallbackData: [],
}
);
const onChange = debounce(
useCallback(
(e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value),
[value]
),
500
);
if (error) {
return <div>An error occured</div>;
}
return (
<div className={styles.container}>
<input onChange={onChange} />
{data?.map((e: any) => (
<div key={Math.random()}>{e.name}</div>
))}
</div>
);
}
IMPORTANT: value cannot be passed to input. Just pass onChange method.
On API side with fake data, filepath /pages/api/user/[name].ts:
import type { NextApiRequest, NextApiResponse } from "next";
type Data = {
name: string;
};
const data: Array<Data> = [
{ name: "John Doe" },
{ name: "Miss Pierce Bogisich" },
{ name: "Beaulah Tillman" },
{ name: "Aracely Hessel" },
{ name: "Margret Berge" },
{ name: "Hailee Macejkovic" },
{ name: "Lazaro Feeney" },
{ name: "Gennaro Rutherford" },
{ name: "Ian Hackett" },
{ name: "Sonny Larson" },
{ name: "Dr. Liza Wolf" },
];
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Array<Data>>
) {
const {
query: { name },
} = req;
console.log(name);
res
.status(200)
.json(
data.filter((e) =>
e.name.toLowerCase().includes(`${name?.toString().toLowerCase()}`)
)
);
}
I have a response from my mongodb database as the following
{_id: '61ca4273e7cc1da1f3dbc9a3', title: 'Hero Syndrome', slug: 'hero-syndrome', category: 'Game', release_date: null, … }
I'm using Redux to fetch the data.
When I do console.log(game) which is the Object I provided, the console return the Object indeed. But when I'm trying to access the children such as title or slug it doesn't work.
I used to have this error Objects are not valid as a React child .. but fixed it somehow randomly in the code.
Any idea how to access title for example ?
What I tried : {title}, title, {game.title} and none of them work
What I did to get data from Redux :
GameComponent.propTypes = {
game: PropTypes.object.isRequired,
};
const mapStateToProps = state => ({
game: state.game,
});
And at the top of the component
function GameComponent({
game: { game, loading, title },
}) { ....
I tried to convert the object to string and to array in order for React to read it but I failed.
Code :
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { getGameByToken } from '../actions/game';
import GameOverview from './GameOverview';
function GameComponent({ game: { game, loading, title }, getGameByToken, auth }) {
useEffect(() => {
getGameByToken(token);
}, [getGameByToken, token]);
return <>
//this doesn't work
Title : {title}
</>;
}
GameComponent.propTypes = {
getGameByToken: PropTypes.func.isRequired,
game: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
game: state.game,
auth: state.auth,
});
export default connect(mapStateToProps, { getGameByToken })(GameComponent);
Response from database in redux :
import axios from 'axios';
import { setAlert } from './alert';
import { GET_GAME, GAME_ERROR } from './types';
// GET GAMES BY TOKEN
export const getgameByToken = (token) => async (dispatch) => {
try {
const res = await axios.get('/api/games/' + token);
dispatch({ type: GET_GAME, payload: res.data });
} catch (err) {
dispatch({
type: GAME_ERROR,
payload: {
msg: err.response.msg,
status: err.response.status,
},
});
}
};
From Redux Dev Tools :
EDIT: If I rename game: state.game, to game: state.game.game, I actually got the value ! But when refreshing It goes back saying TypeError: Cannot read properties of null (reading 'title')
I have been using stripe checkout in my react application for about a week now. However, I now receive an error that says "Stripe Checkout can't communicate with our payment processor because the API key is invalid. Please contact the website owner or support#stripe.com." I have no idea why this is happening now. I just want to be able to send my total into the stripe modal.
stripe.js
import React, { useState } from "react";
import ReactDOM from "react-dom";
import axios from "axios";
import { connect } from "react-redux";
import { purchase } from "../actions/StoreActions";
import { toast } from "react-toastify";
import StripeCheckout from "react-stripe-checkout";
const mapStateToProps = (state) => {
return {
cart: state.cart,
total: state.total
};
};
const mapDispatchToProps = (dispatch) => {
return {
purchase: (order) => {
dispatch(purchase(order));
}
};
};
function Stripe(props) {
console.log(props);
const [product] = React.useState({
name: `$${props.total}`,
price: props.total
});
async function handleToken(token, address) {
props.startLoading();
const response = await axios.post(
"https://storebe.herokuapp.com/checkout",
{
token,
product
}
);
const { status } = response.data;
if (status === "success") {
props.stopLoading();
console.log(address);
purchaseCartItems(address);
} else {
props.stopLoading();
toast("Failed, please try again", { type: "error" });
}
console.log(response.data);
}
return (
<div className="container">
<StripeCheckout
stripeKey="pk_test_51HF9J6FriexrfnPAT0b3P1wDiKx1YQzONJrB5F4ksTidko10JKZOTgo7zuPjj9NWquykYNnMz1GRyQ5LDI2HvrEF00U49BhKdn"
token={handleToken}
amount={props.total * 100}
billingAddress
shippingAddress
name={product.name}
/>
</div>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(Stripe);
There isn't a way to validate if an API key is actually a valid Stripe API key.
The issue on your end is most likely because the publishable key in your code has a typo in it.
You just have to make sure that the API keys you copy from https://dashboard.stripe.com/test/apikeys are correct and don't have any copy paste errors like extra white space, etc.
I am having such a pain with such a small issue. I am integrating Launch Darkly which takes a certain number of parameters for it work during the export. My export is as follows:
export default withLDProvider({
clientSideID,
user: {
key: userId,
custom: {
siteId: site,
},
},
})(App);
Now, clientSideID, userId, and site are part of my props which i need to assign to it.
I have tried the following:
export default (props) => {
const { auth: { userId, site } } = props.store.getState();
return withLDProvider({
clientSideID,
user: {
key: userId,
custom: {
siteId: site,
},
},
})(App);
};
but i get the following error:
index.js:2178 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
in Component (created by Connect(Component))
in Connect(Component) (created by HotExportedConnect(Component))
in AppContainer (created by HotExportedConnect(Component))
in HotExportedConnect(Component) (at src/index.js:33)
in ErrorBoundary (at src/index.js:33)
help?
I'm confused, are you trying to create a component or a function? If you are creating a function, then you would not be sending props to it. If you are creating a component (call it like: <withLDProvider props={x} />), then maybe this will do what you want:
import React from "react";
const withLDProvider = props => {
const { userId, site } = props;
return (
{
clientSideID,
user: {
key: userId,
custom: {
siteId: site,
},
},
}
)
}
export default withLDProvider;
I am calling an API server from my redux project where I want to extract the data.The data in the API is in the form as shown below:
const defaultData = {
categories: [
{
name: 'react',
path: 'react'
},
{
name: 'redux',
path: 'redux'
},
{
name: 'udacity',
path: 'udacity'
}
]
}
So, in my redux "Actions", I am using axios to make the API call.The actions file is given below:
import axios from 'axios';
export const FETCH_CATEGORIES = 'fetch_categories';
let token;
if (!token)
token = localStorage.token = Math.random().toString(32).substr(-8);
const API = 'http://localhost:3001';
const headers = {
'Accept' : 'application/json',
'Authorization' : 'token'
}
export function fetchCategories() {
const URL = `${API}/categories`;
const request = axios.get(URL,{headers});
return dispatch => {
return request.then((data) => {
dispatch({
type : FETCH_CATEGORIES,
payload : data
})
})
}
}
I am trying to save the result of the API call in the application state in my reducer.The Reducer for the categories looks like this:
import _ from 'lodash';
import { FETCH_CATEGORIES } from '../actions/categories_action';
export default function(state={}, action) {
switch(action.type) {
case FETCH_CATEGORIES:
return {categories: {...state.categories, ...action.payload}};
default:
return state;
}
}
And I am using combineReducers() to combine all the reducers in my index file as shown below:
import { combineReducers } from 'redux';
import PostReducer from './PostsReducer';
import CategoriesReducer from './CategoriesReducer';
const rootReducer = combineReducers({
loading: false,
posts: PostReducer,
categories: CategoriesReducer
});
export default rootReducer;
Then, in my component I am trying to show the data from the state.
So,when I try to console.log the value of the categories state, I get something like this as shown in the image below:
But I just want the categories property where I get the three categories(I want to omit the config,headers,request properties).
I even tried something like: console.log(this.props.categories.data.categories) ,but that gives me an undefined value.
Can anyone please help me with this?
That is because of this line {categories: {...state.categories, ...action.payload}};
Change that to {categories: [...state.categories, ...action.payload.data.categories]};