I'm learning vuex at the moment and wondering if there is a way to pass a different endpoint url in my vuex action? I'm building a simple movie app using a movies API and have numerous buttons that will call the API and post specific categories. What I would like to do is dispatch the same function from vuex but specify which endpoint to use rather than create the same function with just a different endpoint in vuex.
Vuex:
import axios from 'axios'
const topTwentyEndpoint =
'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key='
const theatresEndpoint =
'https://api.themoviedb.org/3/discover/movie?primary_release_date.gte=2014-09-15&primary_release_date.lte=2014-10-22&api_key='
export const state = () => ({
posts: [],
})
export const mutations = {
setMovies(state, posts) {
state.posts = posts
},
}
export const getters = {}
export const actions = {
getMovies({ commit }) {
axios.get(topTwentyEndpoint).then((response) => {
commit('setMovies', response.data.results)
})
},
}
movies component:
<template>
<form
id="formGetMovies"
class="flex flex-col items-start w-3/4 pt-5 get-movies"
>
<div class="flex buttons__row">
<button
class="py-3 mt-2 mr-5 text-white bg-red-700 rounded-md hover:bg-red-800 px-7 btn btn__submit btn-disabled"
:class="{ disabled: moviesShown }"
:disabled="moviesShown"
#click.prevent="submitForm"
>
Top 20
</button>
<button
class="py-3 mt-2 text-white bg-red-700 rounded-md hover:bg-red-800 px-7 btn btn__submit btn-disabled"
:class="{ disabled: moviesShown }"
:disabled="moviesShown"
#click.prevent="submitForm"
>
In Theatres Now
</button>
</div>
</form>
</template>
<script>
export default {
name: 'MoviesForm',
data() {
return {
moviesShown: false,
}
},
methods: {
submitForm() {
this.$store.dispatch('movies/getMovies')
this.moviesShown = true
},
},
}
</script>
Related
*is it possible to integrate in my ready checkout paypal code to add monthly payment function?
I have developed a function that is responsible for receiving a one-time payment, but I need to add a function that will be responsible for charging a monthly fixed amount from a person who wants to make a monetary contribution
*
import React, { useEffect } from "react";
import {
PayPalScriptProvider,
PayPalButtons,
usePayPalScriptReducer,
} from "#paypal/react-paypal-js";
import imgLogo from "../../../images/FUMlogo.png";
import imgColageDesk from "../../../images/Donate/colageDesk.png";
import DonateBTN from "../../UI/Button/DonateBTN/DonateBTN";
import DonateOther from "../../UI/Button/DonateBTN/DonateOther";
import { useDispatch, useSelector } from "react-redux";
import {
setAmountMoney,
setFlowAmountMoney,
} from "../../../Store/Reducers/inputMoneyAmount";
export default function Donate() {
const amountDonate = useSelector((state) => state.inputMoneyAmount.amount);
const flowAmountDonate = useSelector(
(state) => state.inputMoneyAmount.flowAmount
);
const dispatch = useDispatch();
const amount50 = () => {
dispatch(setFlowAmountMoney(false));
dispatch(setAmountMoney(50));
};
const amount100 = () => {
dispatch(setFlowAmountMoney(false));
dispatch(setAmountMoney(100));
};
const amount200 = () => {
dispatch(setFlowAmountMoney(false));
dispatch(setAmountMoney(200));
};
// This values are the props in the UI
const amount = amountDonate ? amountDonate : flowAmountDonate + "";
const currency = "USD";
const style = { layout: "vertical", color: "blue" };
// Custom component to wrap the PayPalButtons and handle currency changes
const ButtonWrapper = ({ currency, showSpinner }) => {
// usePayPalScriptReducer can be use only inside children of PayPalScriptProviders
// This is the main reason to wrap the PayPalButtons in a new component
const [{ options, isPending }, dispatch] = usePayPalScriptReducer();
useEffect(() => {
dispatch({
type: "resetOptions",
value: {
...options,
currency: currency,
},
});
}, [currency, showSpinner]);
return (
<>
{showSpinner && isPending && <div className="spinner" />}
<PayPalButtons
style={style}
disabled={false}
forceReRender={[amount, currency, style]}
fundingSource={undefined}
createOrder={(data, actions) => {
return actions.order
.create({
purchase_units: [
{
amount: {
currency_code: currency,
value: amount,
},
},
],
})
.then((orderId) => {
// Your code here after create the order
return orderId;
});
}}
onApprove={function (data, actions) {
return actions.order.capture().then(function () {
// Your code here after capture the order
});
}}
/>
</>
);
};
// bg-[#010321]
return (
<main className="flex flex-col items-center w-full h-screen sm:h-auto text-white bg-[#1b1d33] pt-[8vh] sm:pt-[9vw] lg:pt-[7vw] xl:pt-[5vw] relative ">
<section className=" flex flex-col items-center justify-center px-[3vw] ">
<img
className=" w-full sm:w-[70vw] md:w-[60vw] lg:w-[40vw] xl:w-[30vw]"
src={imgColageDesk}
alt="colage"
/>
<img
className="w-[10vw] lg:w-[8vw] xl:w-[5vw] h-[10vw] lg:h-[8vw] xl:h-[5vw] mt-10"
src={imgLogo}
alt="logo"
/>
<h3 className="text-xs sm:text-sm md:text-base lg:text-lg mt-5">
Donate to
</h3>
<h1 className="uppercase mt-3 text-sm sm:text-base md:text-lg lg:text-xl font-bold ">
forward ukraine ministries
</h1>
<p className="w-full sm:w-[70vw] md:w-[60vw] lg:w-[40vw] xl:w-[30vw] text-center text-xs sm:text-sm md:text-base lg:text-lg mt-2">
A humanitarian catastrophe is unfolding in Ukraine as attacks of war
put millions of lives at risk. Support Military & Refugee
</p>
<div className="w-[80vw] sm:w-[50vw] md:w-[30vw] flex justify-around mt-14 mb-4 sm:mt-15 text-black">
<DonateBTN setAmount={amount50} amount="$50" />
<DonateBTN setAmount={amount100} amount="$100" />
<DonateBTN setAmount={amount200} amount="$200" />
<DonateOther name="Other" />
</div>
<input
value={flowAmountDonate}
onChange={(e) => dispatch(setFlowAmountMoney(e.target.value))}
onKeyDown={(e) =>
["ArrowUp", "ArrowDown", "e", "E", "+", "-", ".", ","].includes(
e.key
) && e.preventDefault()
}
className={`${
flowAmountDonate
? "block font-bold w-[80%] sm:w-3/4 md:w-[85%] h-[7vw] sm:h-[6vw] md:h-[4vw] mb-4 sm:mb-8 text-black rounded-lg bg-gradient-to-r from-blue-500 to-yellow-500 focus:from-pink-500 focus:to-yellow-500 hover:from-pink-500 hover:to-yellow-500"
: "hidden"
}`}
type="number"
name=""
/>
<PayPalScriptProvider
options={{
"client-id": "test",
components: "buttons",
currency: "USD",
}}
>
<ButtonWrapper currency={currency} showSpinner={false} />
</PayPalScriptProvider>
</section>
</main>
);
}
Recurring payments use a separate process.
For react-paypal-js in particular you can see an example of a Subscription checkout here. You can create subscription plans in your live PayPal account here (or for a sandbox business account here, or via API here). The client-id that a subscription plan is created for must correspond to the client-id that the JS SDK is loaded with for checkout. If it does not correspond, the error will be RESOURCE_NOT_FOUND.
I am building Pokemon filtered search app using Vue 3 with Composition API, based on the following tutorial: https://www.youtube.com/watch?v=QJhqr7jqxVo. The Home view in the app uses a fetch method to fetch Pokemon from the PokemonAPI:
fetch('https://pokeapi.co/api/v2/pokemon?offset=0')
.then((res)=> res.json())
.then((data)=> {
console.log(data)
state.pokemons = data.results;
state.urlIdLookup = data.results.reduce((acc, cur, idx)=>
acc = { ...acc, [cur.name]:idx+1 }
,{})
})
Each Pokemon in the JSON response includes an index number. The second promise uses a reduce method to handle urlIdLookup. urlIdLookup is then passed into the router-link path used to redirect to Pokemon about/details page:
<div class="ml-4 text-2x text-blue-400"
v-for="(pokemon, idx) in filteredPokemon" :key="idx">
<router-link :to="`/about/${urlIdLookup[pokemon.name]}`">
{{ pokemon.name }}
</router-link>
</div>
The tutorial, however, does not explain why it is necessary to create a new accumulator object ("acc") inside the reduce method, and then deconstruct the accumulator ("...acc"). Could someone perhaps explain why it's necessary to create that object, then deconstruct it? Also, is there perhaps a better method for retrieving the id and passing it into the router link?
Here is the full component:
<template>
<div class="w-full flex justify-center">
<input type="text" placeholder="Enter Pokemon here"
class="mt-10 p-2 border-blue-500 border-2" v-model="text"/>
</div>
<div class="mt-10 p-4 flex flex-wrap justify-center">
<div class="ml-4 text-2x text-blue-400"
v-for="(pokemon, idx) in filteredPokemon" :key="idx">
<router-link :to="`/about/${urlIdLookup[pokemon.name]}`">
{{ pokemon.name }}
</router-link>
</div>
</div>
</template>
<script>
import { reactive, toRefs, computed } from 'vue';
export default {
name: 'Home',
setup() {
const state = reactive({
pokemons: [],
urlIdLookup:{},
text: "",
filteredPokemon: computed(()=> updatePokemon())
})
const updatePokemon = () => {
if(!state.text) {
return []
}
return state.pokemons.filter((pokemon) =>
pokemon.name.includes(state.text)
)
}
fetch('https://pokeapi.co/api/v2/pokemon?offset=0')
.then((res)=> res.json())
.then((data)=> {
console.log(data)
state.pokemons = data.results;
state.urlIdLookup = data.results.reduce((acc, cur, idx)=>
acc = { ...acc, [cur.name]:idx+1 }
,{})
})
return { ...toRefs(state), updatePokemon }
}
}
</script>
I am using React Query to make API calls.
I have an OTP Generation API in which I am making a POST API call to generate an OTP as a response from the API I receive the status of OTP deliverance.
/* eslint-disable no-unused-vars */
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { TextField } from '../Input/TextField';
import { CustomButton } from '../Button/CustomButton';
import { MOBILE_NUMBER } from '../Common/Placeholder';
import { getOtpData } from '../../hooks/getOtp.hook';
export function MobileNumber() {
const navigate = useNavigate();
const [mobileno, setMobileNo] = useState('');
const [isTermsAgree, setisTermsAgree] = useState(false);
const [isDisplayLoader, setDisplayLoader] = useState(false);
const [isDisplayError, setDisplayError] = useState(false);
const { mutate, isError, isSuccess, isLoading, isIdle, data } =
getOtpData();
// Onchnage event for input mobile number
const handleNumberChange = (
e: React.ChangeEvent<HTMLInputElement>,
) => {
setMobileNo(e.target.value);
};
// Onchnage event for Checkbox
const TermsAgreeChange = () => {
setisTermsAgree((current) => !current);
};
// onClick Event Confirm Btn //Generate OTP API call Goes Here
const getOtp = () => {
mutate(mobileno);
if (isSuccess) {
if (data?.data.otpSent) {
console.log('Sent - true');
navigate('/phone-otp-confirmation', {
state: { phoneNumber: mobileno },
});
}
if (data?.data.maxOtpRetriesExceeded) {
setDisplayError(true);
}
}
if (isError) {
console.log('error');
}
};
return (
<div className="bg-grey-800 h-1/2 mt-40 flex flex-col justify-evenly font-Manrope ">
<section>
<div className=" flex-col flex items-center md:items-baseline md:pl-36 ">
<p className=" text-3xl "> Enter Mobile Number </p>
</div>
<div>
<p className="text-l flex-col flex items-center mt-1 md:items-baseline md:pl-36 ">
<span className=" text-gray-400 text-center ">
Enter Mobile Number used for instant login
</span>
</p>
</div>
<div className="flex-col flex items-center md:items-baseline md:pl-36 mt-5">
<div className=" flex items-center sm:justify-start sm:px-0 ">
<div>
<div className=" flex w-18 px-3 justify-center items-center bg-transparent rounded-bl-lg rounded-tl-lg border text-2xl md:text-3xl border-gray-700 h-12 md:h-16 focus:outline-none focus:bg-transparent">
<span>+91</span>
</div>
</div>
<div>
<TextField
width="w-48"
height="h-12"
padding="px-5"
placeholder={MOBILE_NUMBER}
maxlen={10}
other="rounded-br-lg rounded-tr-lg px-5 md:w-72 md:h-16"
type="text"
onChangeFunction={handleNumberChange}
val={mobileno}
error={false}
/>
</div>
</div>
</div>
</section>
<div className=" flex-col flex mt-16 items-center md:items-baseline md:pl-36 md:mt-5 ">
<div className="flex items-center w-72">
<TextField
width="w-7"
height="h-7"
type="checkbox"
other="form-checkbox"
onChangeFunction={TermsAgreeChange}
/>
<p className="ml-3 text-sm md:text-base tracking-wide text-gray-400 font-extralight">
I have read the OneCard{' '}
<a
href="http://"
className="underline text-sm md:text-base text-gray-400"
>
Terms and Conditions & Privacy Policy
</a>{' '}
</p>
</div>
<div className="mt-8 ">
<CustomButton
clickEvent={getOtp}
btntext="Get OTP"
isbuttonactive={mobileno.length === 10 && isTermsAgree}
/>
</div>
{/* <h2>Loader</h2>
<h2>Error</h2> */}
</div>
</div>
);
}
OTP Generation hook
import { useMutation } from 'react-query';
import axios from 'axios';
import { WEB } from '../constants/constants';
interface IGetOTPResult {
otpSent: boolean;
maxOtpRetriesExceeded: boolean;
}
const getOTP = async (mobileNumber: string) => {
const response = await axios.post<IGetOTPResult>(
`${process.env.REACT_APP_URL}/`,
{
mobile: mobileNumber
},
{
headers: {
Authorization: '',
'Content-Type': 'application/json',
},
},
);
return response;
};
export const getOtpData = () => {
return useMutation(getOTP);
};
PROBLEM : As soon as I make this API call through the frontend as I click the button, it goes into isIdle state to be true.
Only the second time, I click the button, isSuccess becomes true.
However, bot the times the API call is made and I receive a 200 response!
I want to ensure my API call never enters isIdle state.
Plus, there is no significant information given about isIDle in any of react-queries documentation.
How do I go about this?
This is not how state in react works. when you call mutate, react-query updates state in your component, and on the next render cycle, it will be available. It is the same concept as setState, you can't really do:
function MyComponent() {
const [foo, setFoo] = React.useState('foo')
return <button onClick={() => {
setFoo('something')
console.log(foo) // 🚨 this will still log "foo", not "something"
}}>click</button>
}
if you want to get access directly to the response, you have to either:
use the provided callbacks of mutate:
mutate(
mobileno,
{
onSuccess: (response) => {
// handle success here
},
onError: (error) => {
// handle error here
}
)
use mutateAsync and await:
try {
const response = await mutateAsync(mobileno)
// handle success here
} catch(error) {
// handle error here
}
side question: how can a hook be called getOtpData ? It has to start with use...
I am trying to develop a discussion forum website using React, Node and MongoDB.In post object, there is nested author object and tags array.
Here is sample image of a post object:
here is the component which I am trying to render:
import React, { Component } from "react";
import http from "../services/httpService";
import { postEndPoint, repliesEndPoint } from "../config.json";
class PostPage extends Component {
state = {
post: [],
replies: [],
};
async componentDidMount() {
const id = this.props.match.params.id;
const { data: post } = await http.get(postEndPoint + "/" + id);
const { data: replies } = await http.get(repliesEndPoint + "/" + id);
console.log(post.tags, typeof post.tags);
this.setState({ post: post, replies: replies });
}
render() {
const { post, replies } = this.state;
return (
<React.Fragment>
<div className="container col-lg-8 shadow-lg p-3 mt-5 bg-body rounded">
<h2>{post.title}</h2>
<p className="mt-4" style={{ color: "#505050" }}>
{post.description}
</p>
<div className="mt-1">
Related Topics:
{post.tags.map((tag) => (
<span className="badge badge-secondary m-1 p-2">
{(tag).name}
</span>
))}
<h6 className="mt-2">
{post.upvotes.length} Likes {post.views} Views
</h6>
<div class="d-flex w-100 justify-content-between">
<small class="mb-1">Posted by {post.author['name']}</small>
</div>
</div>
</div>
</React.Fragment>
);
}
}
export default PostPage;
This throws the following : TypeError: post.tags is undefined. a Similar error is throws while accessing post.upvotes and post.author
Since you do your http request in 'componentDidMount' a render occured at least once before. So react tried to read post.something and it was still undefined.
And even if you do it before an http request is asynchronous so be careful
You need to check that post.something is defined before you use.
Also your initialisation if confusing you initialize post as an array but you are trying to do post.title.
If post is really an array then post.map() won't crash on an empty array.
If it's an object check that is it defined correctly.
Try this as initial state
state = {
post: {
description:"",
title:"",
tags: [],
author:[] ,
upvotes:[] ,
views : 0
},
}
initial state for post is {}
state = {
post: { tags: [] },
replies: [],
};
You can have a simple if condition added. So it will only loop through that if it is present. Check this.
import React, { Component } from "react";
import http from "../services/httpService";
import { postEndPoint, repliesEndPoint } from "../config.json";
class PostPage extends Component {
state = {
post: [],
replies: [],
};
async componentDidMount() {
const id = this.props.match.params.id;
const { data: post } = await http.get(postEndPoint + "/" + id);
const { data: replies } = await http.get(repliesEndPoint + "/" + id);
console.log(post.tags, typeof post.tags);
this.setState({ post: post, replies: replies });
}
render() {
const { post, replies } = this.state;
return (
<React.Fragment>
<div className="container col-lg-8 shadow-lg p-3 mt-5 bg-body rounded">
<h2>{post.title}</h2>
<p className="mt-4" style={{ color: "#505050" }}>
{post.description}
</p>
<div className="mt-1">
Related Topics:
{post.tags && post.tags.map((tag) => ( // <--- map will only execute when it finds tags.
<span className="badge badge-secondary m-1 p-2">
{(tag).name}
</span>
))}
<h6 className="mt-2">
{(post.upvotes && post.upvotes.length) || 0} Likes {post.views} Views // <---- These default values too will handle the case where the data isnt ready yet
</h6>
<div class="d-flex w-100 justify-content-between">
<small class="mb-1">Posted by {post.author['name']}</small>
</div>
</div>
</div>
</React.Fragment>
);
}
}
export default PostPage;
I am trying to use Howler.js in Reactjs using typescript.
I can able to play the sound but it does not pause or stop. Here is my code.
This a component where I am passing all the audio details using props.
I did console.log() to check, is it going in else part and it goes and print the console.
Please help me in this
import React, { useState } from 'react';
import Button from 'components/button/button';
import PlayIcon from 'assets/icons/play.svg';
import PauseIcon from 'assets/icons/pause.svg';
import AudioWave from 'assets/icons/sound-wave.svg';
import { Howl, Howler } from 'howler';
interface Props {
name?: string,
audio?: any,
loop?: boolean,
autoplay?: boolean
}
const Audio = (props: Props) => {
const { name, audio, loop, autoplay } = props;
const [isPlaying, setIsPlaying] = useState(false);
const [audioId, setAudioId] = useState(0);
const sound = new Howl({
src: [audio],
autoplay: autoplay,
loop: loop,
volume: 1,
onend: function () {
setIsPlaying(false);
},
});
Howler.volume(0.5);
const playAudio = () => {
let Id: any;
if (!isPlaying) {
Id = sound.play();
setAudioId(Id);
setIsPlaying(true);
console.log('THS')
} else {
sound.stop(audioId);
console.log('THATAT', audioId)
}
console.log(sound)
}
return (
<div className="flex flex-col items-center justify-center rounded shadow-md w-full">
{console.log(isPlaying, audioId)}
<div className="grid grid-cols-12 w-full">
<div className="col-span-6 p-2">
<p className="text-left">
{name}
</p>
</div>
<div className="col-span-6 p-2">
<p className="text-right text-light-gray">
{sound ? `${Duration.toTimeFormat(sound._duration * 1000)}s` : '0:00s'}
</p>
</div>
</div>
<div className="grid grid-cols-12 w-full items-center justify-center">
<div className="grid col-span-2 w-full p-2">
<img
className="w-full cursor"
onClick={() => playAudio()}
src={isPlaying ? PauseIcon : PlayIcon}
alt="PlayPauseIcon"
/>
</div>
<div className="grid col-span-10 p-2">
<img className="w-full" alt="Audio Wave" src={AudioWave} />
</div>
</div>
</div>
)
}
export default Audio;
I'm not too familiar with Howler, but it seems it's not 'react-friendly' - more suited for a non-SPA environment. However, I figure if you try it like this, you might get the results you're looking for. The main issue with your code is that every time you change something via useState, the component will re-render. When it re-renders, any variables that are not stored via useState, will have their values re-initialized. Therefore, in your code from the question, the sound variable gets reset on every render making it impossible to control the element. In the code below I shifted that into a useEffect function, which is similar to componentDidMount. It will only run on the first render; thus, it prevents you from having several copies of the sound object.
I haven't tested this code, but I think in general it targets the main issue you're having.
const Audio = (props: Props) => {
const { name, audio, loop, autoplay } = props;
const [isPlaying, setIsPlaying] = useState(false);
const [audioId, setAudioId] = useState(0);
const [sound, setSound] = useState(null);
useEffect(() => {
const s = new Howl({
src: [audio],
autoplay: autoplay,
loop: loop,
volume: 0.5,
onplay: function (id) {
setAudioId(id);
setIsPlaying(true);
},
onpause: function (id) {
setIsPlaying(false);
},
onend: function () {
setIsPlaying(false);
},
onloaderror: function(id, error) {
console.log(`a load error has occured on id ${id}`);
console.error(error);
},
onplayerror: function(id, error) {
console.log(`a play error has occured on id ${id}`);
console.error(error);
}
});
setSound(s);
});
const toggleAudioState = () => {
if (sound !== null) {
if (!isPlaying) {
sound.play();
setIsPlaying(true);
} else {
sound.stop(audioId);
}
}
}
return (
<div className="flex flex-col items-center justify-center rounded shadow-md w-full">
<div className="grid grid-cols-12 w-full">
<div className="col-span-6 p-2">
<p className="text-left">
{name}
</p>
</div>
<div className="col-span-6 p-2">
<p className="text-right text-light-gray">
{sound ? `${Duration.toTimeFormat(sound._duration * 1000)}s` : '0:00s'}
</p>
</div>
</div>
<div className="grid grid-cols-12 w-full items-center justify-center">
<div className="grid col-span-2 w-full p-2">
<img
className="w-full cursor"
onClick={() => toggleAudioState()}
src={isPlaying ? PauseIcon : PlayIcon}
alt="PlayPauseIcon"
/>
</div>
<div className="grid col-span-10 p-2">
<img className="w-full" alt="Audio Wave" src={AudioWave} />
</div>
</div>
</div>
)
}
I got the solution for that : -
Here it should be define global. But we can't do it in react, because we are receiving all the data through props.
const sound = new Howl({ } );
If we define this able the function then it will work -
const sound = new Howl({
src: ['some_music_link.mp3'],
autoplay: true,
loop: true,
volume: 1,
});
const Audio = (props :Props) => {
...
}
In order to solve this problem someone created a new npm package for that called Router Howler
So, if you are trying to use howler.js in react then use React Howler