dispatch argument to returned function - javascript

I am dispatching a function like the following:
ChartHandlePureFunc.js:
export function getBasic() {
return async (dispatch) => {
const response = await axios.get
`https://financialmodelingprep.com/api/v3/historical-price-full/AAPL?apikey=*********`;
dispatch(changeValue(response.data));
};
}
ChartHandler.js:
useEffect(() => {
if (!req) {
dispatch(getBasic());
}
}, [req]);
The above code works and the only thing I am trying to change is for getBasic to be able to take an argument and be dispatched like the following:
export function getBasic(userInput) {
return async (dispatch) => {
const response = await axios.get(`https://financialmodelingprep.com/api/v3/historical-price-full/${userInput}?apikey=*********`);
dispatch(changeValue(response.data));
};
}
And then in my other components useEffect:
useEffect(() => {
if (!req) {
dispatch(getBasic('AAPL'));
}
}, [req]);
Since the argument is only getting used in the getBasic function I believe this is all the code required for the problem, I have also tried having userInput next to dispatch like:
return async (dispatch, userInput) => {
...
};
And have tried that with both userInput still being in the getBasic argument and without.
Edit:
console.log(userInput) when userInput is in the getBasis arg like: getBasic(userInput) I get AAPL, the correct result in console, but if I move it down to return async (dispatch, userInput) I then get
ƒ i() {
var e,
r = (e =
t.getState()).computedStates[e.currentStateIndex].state;
return void 0 !== r && (n = r), n;
}
in console

You can take the param and make a template string like this:
export function getBasic(userInput) {
const requestUrl = `https://financialmodelingprep.com/api/v3/historical-price-full/${userInput}?apikey=*********`;
return async (dispatch) => {
const response = await axios.get(requestUrl);
dispatch(changeValue(response.data));
};
}

Related

React custom hook returning array and utilize the same in App component

I have my App component defined as below;
function App() {
const [state1, setState1] = useState({});
const [state2, setState2] = useState({});
const [isApiCallDone, setIsApiCallDone] = useState(false);
const fetchFn = useMyCustomFetch();
useEffect(() => {
(async function() {
try {
let [state11] = await fetchFn('api/api1', {}, 'GET');
let [state22] = await fetchFn('api/api2', {}, 'GET');
setState1(state11); // Is there a better way to set this ?
setState2(state22);
setIsApiCallDone(true);
} catch (e) {
console.error(e);
}
})();
}, []);
useEffect(() => {
if (Object.keys(state1).length > 0 && Object.keys(state2).length > 0) {
// Set some other state variables on App
}
}, [state1, state2])
return (
<>
<MyContextProvider>
{isApiCallDone && (
<MyComponent />
)
}
</MyContextProvider>
</>
}
Also my useMyCustomFetch hook looks like below
export default function useMyCustomFetch() {
const fetchData = async (url, reqData, reqType) => {
try {
var statusObj = {
statMsg: null
};
const response = await fetch(url, reqOptions);
if (!response.ok) {
throw response;
}
statusObj.status = "success";
const json = await response.json();
return [json, statusObj];
} catch (error) {
statusObj.status = "error";
return [null, statusObj];
}
}
return fetchData;
}
My questions are;
For the lines
let [state11] = await fetchFn('api/api1', {}, 'GET');
setState1(state11);
I first assign it to a new variable state11 and then assign the same by calling setState1.
Is there a better way to set the state1 directly?
Is the usage of async function inside the useEffect fine ?
For Question 1:
You can directly setState like below without using state11.
useEffect(() => {
(async function () {
try {
setState1(
(await fetchFn("https://reqres.in/api/users/1", {}, "GET"))[0]
); // Is there a better way to set this ?
setState2(
(await fetchFn("https://reqres.in/api/users/2", {}, "GET"))[0]
);
setIsApiCallDone(true);
} catch (e) {
console.error(e);
}
})();
}, []);
For Question 2:
I don't see any problem using async & IIFE in the useEffect. In fact I like the way its done. Looks good to me.
Please find screenshot of the state being set properly in the console (I have used a dummy api url):
If you don't want to use async functions, you can use the Promise.prototype.then() method to combine your calls like this :
useEffect(() => {
fetchFn('api/api1', {}, 'GET').then(state => {
setState1(state[0]);
return fetchFn('api/api2', {}, 'GET')
}).then(state => {
setState2(state[0]);
setIsApiCallDone(true);
}).catch(console.log);
}, []);
An other way to set this with an async function but more factorised is this way :
useEffect(() => {
(async function() {
try {
await fetchFn('api/api1', {}, 'GET')
.then(tab => tab[0])
.then(setState1);
await fetchFn('api/api2', {}, 'GET');
.then(tab => tab[0])
.then(setState2);
setIsApiCallDone(true);
} catch (e) {
console.error(e);
}
})();
}, []);
Finally, the usage of the async function in an useEffect is not a problem.

Why useState variable gets undefined inside try catch statement in an asynchrone function?

I create a hook that manages the state of a single object with fetch to api. This hook exposes function to interact with this object.
// the hook
const useMyHook = () => {
const [myObject, setMyObject] = useState(null);
useEffect(() => {
const fetchData = async () => {
const data = await fetchSomething();
setMyObject(data);
}
fetchData();
}, []);
const updateMyObject = async () => {
console.log(myObject); // log : { ... }
try {
console.log(myObject); // log : undefined
// ...
} catch(err) {
// ...
}
};
return {
updateMyObject,
myObject
};
};
Then i use this hook inside a component and trigger updateMyObject() with a button.
// the component
const MyComponent = () => {
const { myObject, updateMyObject } = useMyHook();
return (
<button onClick={updateMyObject}>
Click me
</button>
);
};
How is this possible that before the try catch block the log is clean and inside the block i get undefined ?
I think this gonna work
useEffect(() => {
const fetchData = async () => {
const data = await fetchSomething();
setMyObject(data);
}
If(!myObject)
fetchData();
}, [myObject]);
Your code is perfectly alright !! There could be a problem in the fetchSomething() method. Ideally, it should return data, but it's not doing the same job.
Here is a small example. You can give it a try.
const fetchSomething = async () => {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts/1"
).then((res) => res.json());
return response;
};

Redux - Asynchronous response from web socket request

I have a websocket interface which I implemented so that I can use to send requests.
The problem is that the response is asynchronous and it initially returns the empty array because retObj is not updated from the callback function that I sent in. How can I make this function so that it will return the populated array when it has been updated.
This is how my Service looks like:
import * as interface from '../webSocket'
const carService = () => {
return {
getCars: () => {
interface.sendRequest(function (returnObject) {
//
}).then(d => d)
}
}
}
export default carService()
And this is how my action looks like:
import { GET_CARS } from '../constants'
import carService from '../carService'
export const getCars = () => async (dispatch) => {
try {
const cars = await carService.getCars()
console.log("At cars actions: ", cars) // logs: Array []
dispatch(getCarsSuccess(cars))
} catch (err) {
console.log('Error: ', err)
}
}
const getCarsSuccess = (cars) => ({
type: GET_CARS,
payload: cars
})
You simply have to wrap your callback into promise, since it was not a promise to begin with, which is why you cannot use then or await
import * as interface from '../webSocket'
const carService = () => {
return {
getCars: () => {
return new Promise(resolve => interface.sendRequest(function (returnObject) {
resolve(returnObject.msg)
}));
}
}
}
export default carService()
The problem is, you cant await a function unless it returns a Promise. So, as you can guess, the problem lies in carService.getCars's definition. Try this:
getCars: () => {
return new Promise((resolve, reject) => {
interface.sendRequest(function(returnObject) {
// if theres an error, reject(error)
resolve(returnObject);
})
})
}
Or, if sendRequest os am async function, simply return the return value of sendRequest:
getCars: () => {
return interface.sendRequest()
}

return (dispatch) do nothing

i have a component which run this
import { handleAddQuestion } from '../actions/questions';
handleAddQuestion(optionOneText, optionTwoText, author)
in actions/questions i have
import { _saveQuestion } from '../utils/_DATA';
export function handleAddQuestion (optionOneText, optionTwoText, authedUser) {
console.log("before")
return (dispatch) => {
console.log("after")
_saveQuestion({optionOneText, optionTwoText, author: authedUser}).then((question) => {
let qid = question.id
dispatch(saveUserQuestion(authedUser, qid))
dispatch(addQuestion(question))
})
}
}
i get before in console but not after no action is triggered, nothing happens at all no matter what i change ,, it's like i cannot do this return (dispatch) !! i tried the same thing in another place which worked perfectlly, logged the data and triggered the actions ! what is wrong here !!!!!!!
more info _DATA_.js
export function _saveQuestion (question) {
return new Promise((res, rej) => {
const authedUser = question.author;
const formattedQuestion = formatQuestion(question);
setTimeout(() => {
questions = {
...questions,
[formattedQuestion.id]: formattedQuestion
}
users = {
...users,
[authedUser]: {
...users[authedUser],
questions: users[authedUser].questions.concat([formattedQuestion.id])
}
}
res(formattedQuestion)
}, 1000)
})
}
reducers/questions.js
export function questions(state = {}, action) {
switch (action.type) {
case ADD_QUESTION:
const { question } = action;
return {
...state,
[question.id]: question,
};
///
any help ?
You are returning what is called a thunk here - and thunks only get executed when actually being dispatched. Compare that with how it is called in the other places.
So correct would be calling
dispatch(handleAddQuestion(optionOneText, optionTwoText, author))

Is this a valid recursive function?

I found a recursive expression in a library very confused.
The code is here :
https://github.com/tappleby/redux-batched-subscribe/blob/master/src/index.js#L22
export function batchedSubscribe(batch) {
if (typeof batch !== 'function') {
throw new Error('Expected batch to be a function.');
}
const listeners = [];
function subscribe(listener) {
listeners.push(listener);
return function unsubscribe() {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}
function notifyListenersBatched() {
batch(() => listeners.slice().forEach(listener => listener()));
}
return next => (...args) => {
const store = next(...args);
const subscribeImmediate = store.subscribe;
function dispatch(...dispatchArgs) {
const res = store.dispatch(...dispatchArgs);
notifyListenersBatched();
return res;
}
return {
...store,
dispatch,
subscribe,
subscribeImmediate
};
};
}
Specifically this part:
return next => (...args) => {
const store = next(...args);
const subscribeImmediate = store.subscribe;
function dispatch(...dispatchArgs) {
const res = store.dispatch(...dispatchArgs);
notifyListenersBatched();
return res;
}
return {
...store,
dispatch,
subscribe,
subscribeImmediate
};
};
How is this not infinite recursion?
How is this not infinite recursion?
There is absolutely no recursion here. The syntax next => (...args) => … does not translate to
return function next(...args) {
const store = next(...args);
…
but rather to
return function(next) {
return function(...args) {
const store = next(...args);
…
So unless the caller of that function does something weird like var f = batchedSubscribe(…); f(f)(f)…;, it won't call itself.
The reason we both seemed confused by this is because the arrow function, if written as a single statement, implicitly calls return.
So for example a simple function like this:
const add = (a, b) => a + b;
is equivalent to
var add = function(a, b) {
return a + b;
}
Knowing this we can remove the sugar and convert the arrow functions:
return next => function(...args) { // body }
Is really what's going on here, and if we go one step further we get this:
return function(next) {
return function(...args) {
const store = next(...args);
const subscribeImmediate = store.subscribe;
function dispatch(...dispatchArgs) {
const res = store.dispatch(...dispatchArgs);
notifyListenersBatched();
return res;
}
return {
...store,
dispatch,
subscribe,
subscribeImmediate
};
}
}
Both functions that are containing the code are actually nameless. next is a function, but not one of the functions being returned. It is passed as a variable into the first returned function.
There's no recursion here, but rather a lot of function composition, which is to be expected from a library like redux that draws so much from functional programming.

Categories

Resources