Separate functions which depend on each other - reactjs

I am trying to clean up my code an separate into functions that only have one task.
In v1 joinDailyCo(url); was defined inside fetchUrl(). Now I tried to move it out with
const url = fetchUrl();
joinDailyCo(url);
However, as soon I do that, I get the error message:
Unhandled Rejection (TypeError): Cannot read property 'join' of
undefined
const Daily = ({ eventSlug, tableId }) => {
const classes = useStyles();
const iframeRef = useRef();
const dailyRef = useRef();
const joinedRef = useRef();
useEffect(() => {
// Join call
const joinDailyCo = async (url) => {
if (joinedRef.current) {
// This is needed due to it never returning if there wasn't a meeting joined first.
await dailyRef.current.leave();
}
await dailyRef.current.join({ url });
};
// Retrieve dailySessionId and meetingToken.
const fetchUrl = async () => {
try {
const {
data: { dailySessionId, meetingToken },
} = await api.get(
`events/${eventSlug}/space/tables/${tableId}/daily-auth/`
);
const url = `${DAILY_URL}/${dailySessionId}?t=${meetingToken}`;
return url;
// joinDailyCo(url);
} catch (error) {
Sentry.captureException(error);
}
};
const url = fetchUrl();
url && joinDailyCo(url);
}, [eventSlug, tableId]);
useEffect(() => {
dailyRef.current = DailyIframe.wrap(iframeRef.current, {
// showLeaveButton: true,
});
dailyRef.current.on(eventTypes.LEFT_MEETING, () => {
joinedRef.current = false;
});
dailyRef.current.on(eventTypes.JONING_MEETING, () => {
joinedRef.current = true;
});
return () => {
dailyRef.current.destroy();
};
}, []);
return (
<iframe
ref={iframeRef}
className={classes.root}
title="Video Meeting"
allow="camera; microphone; display-capture; fullscreen"
/>
);
};
export default Daily;

Related

issue with Stripe_success _url with Multiple Destination Product Ids

Please I need assistance with a code.
I have a Nextjs dynamic page as my 'stripe_success_url'
Initially I had one product 'courses' whose {id} is beign fetched in the router.query
however, i have created a new product 'ebook' whose {id} is also being fetched in the router.query
I edited the code to differentiate course ID and ebook ID but it is not working yet.
const StripeSuccess = () => {
// state
const [course, setCourse] = useState([]);
const [ebook, setEbook] = useState([]);
const router = useRouter();
const { id } = router.query;
useEffect(() => {
const fetchCourses = async () => {
const { data } = await axios.get('/api/courses');
setCourse(data);
//console.log(data);
};
fetchCourses();
}, [id]);
useEffect(() => {
const fetchEbooks = async () => {
const { data } = await axios.get('/api/ebooks');
setEbook(data);
//console.log(data);
};
fetchEbooks();
}, [id]);
useEffect(() => {
if (id === `${course._id}`) {
const successRequest = async () => {
const { data } = await axios.get(`/api/stripe-success/${id}`);
//console.log(data);
//console.log('SUCCESS REQ DATA', data);
router.push(`/user/course/${data.course.slug}`);
};
successRequest();
}
}, [id]);
useEffect(() => {
if (id === `${ebook._id}`) {
const successEbookRequest = async () => {
const { data } = await axios.get(`/api/stripe-ebooksuccess/${id}`);
//console.log(data);
//console.log('SUCCESS REQ DATA', data);
router.push(`/user/course/${data.ebook.slug}`);
};
successEbookRequest();
}
}, [id]);

Getting a undefined value when trying to match fetch results to people objects

Im working on a star wars api app. I am getting an array of people objects, 10 characters. Who all are their own object with different values. However homeworld, and species are urls. So I have to fetch them and store that data to the correct place. I figured out a way to get the homeworld values to each character. However when I try to do it with species I receive undefined. Would appreciate any help this has been kind of a pain thanks ahead of time !
const [people, setPeople] = useState([]);
const [homeWorld, setHomeWorld] = useState([]);
const [species, setSpecies] = useState([]);
const [nextPageUrl, setNextPageUrl] = useState("https://swapi.dev/api/people/");
const [backPageUrl, setBackPageUrl] = useState('');
const [test, setTest] = useState([]);
const fetchPeople = async () => {
const { data } = await axios.get(nextPageUrl);
setNextPageUrl(data.next);
setBackPageUrl(data.previous);
return data.results;
}
const backPage = async () => {
const { data } = await axios.get(backPageUrl);
setCharacters(data.results);
setNextPageUrl(data.next);
setBackPageUrl(data.previous);
}
// Get People
async function getPeople() {
const persons = await fetchPeople();
const homeWorldUrl= await Promise.all(
persons.map((thing) => axios.get(thing.homeworld)),
);
const newPersons = persons.map((person) => {
return {
...person,
homeworld: homeWorldUrl.find((url) => url.config.url === person.homeworld)
};
});
const newPersons2 = newPersons.map((person) => {
return {
...person,
homeWorld: person.homeworld.data.name
};
});
setPeople(newPersons2);
}
// Get Species
async function getSpecies() {
const persons = await fetchPeople();
const speciesUrl = await Promise.all(
persons.map((thing) => axios.get(thing.species)),
);
const newSwapi = persons.map((person) => {
return {
...person,
species: speciesUrl.find((info) => info.data.url === person.species)
};
});
setTest(newSwapi);
// const newPersons2 = newPersons.map((person) => {
// return {
// ...person,
// homeWorld: person.homeworld.data.name
// };
// });
}
useEffect(() => {
getPeople();
getSpecies();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); ```
Species property of person is a array, so your getSpecies() should be like
async function getSpecies() {
const persons = await fetchPeople();
const speciesUrl = await Promise.all(
persons
.filter((thing) => thing.species.length)
.map((thing) => axios.get(thing.species[0]))
);
const newSwapi = persons.map((person) => {
return {
...person,
species: speciesUrl.find((info) => info.data.url === person.species[0])
};
});
setTest(newSwapi);
}

why is recipe.map not a function?

I am trying to pass data into a component, however I am getting an error it is saying recipe.map is not a component. Would love some help.
const App = () => {
const [recipe, setRecipe] = useState([]);
const appId = `af783d30`;
const appKey = ``;
const url = `https://api.edamam.com/search?q=chicken&app_id=${appId}&app_key=${appKey}&from=0&to=3&calories=591-722&health=alcohol-free`;
console.log(url);
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(url);
setRecipe(res.data);
console.log(res.data);
} catch (err) {
console.error(err);
}
};
fetchData();
}, []);
return (
<div>
{recipe.map((r) => {
return <RecipeCard recipe={r} />;
})}
</div>
);
};
export default App;

How can I run a function when internet connection is established?

The app is a quiz, and if user finishes the round he may send the points in firebase. If user is not connected to internet, I save the points in device memory, so when connection is established the points are send in firebase.
The best would be to let this happen automatically and show a message...
I'm trying to do this in App.js in a useEffect, but it checks only if I refresh the app. I tried withNavigationFocus and useFocusEffect but error: the App.js is unable to get access to navigation....
I could also move the code to WelcomeScreen.js and show a button if connection is established to add the points, but it's not that user friendly.
Any ideas would be appreciated.
Thanks!
useEffect(() => {
const getPoints = async () => {
let points = await AsyncStorage.getItem("savedPoints");
if (!!points) {
const getEmail = async () => {
const userData = await AsyncStorage.getItem("userData");
if (userData) {
const transformedData = JSON.parse(userData);
const { userEmail } = transformedData;
return userEmail;
}
};
const email = await getEmail();
// Give it some time to get the token and userId,
// because saveData needs them.
setTimeout(
async () => await dispatch(dataActions.saveData(email, +points)),
3000
);
await AsyncStorage.removeItem("savedPoints");
}
};
NetInfo.fetch().then(state => {
if (state.isConnected) {
console.log("isConnected");
getPoints();
}
});
}, []);
The solution
WelcomeScreen.js
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
console.log("useEffect welcome");
const unsub = NetInfo.addEventListener(state => {
setIsConnected(state.isConnected);
});
return () => unsub();
}, []);
const getPoints = async () => {
console.log("getPoints welcome");
let points = await AsyncStorage.getItem("savedPoints");
if (!!points) {
const getEmail = async () => {
const userData = await AsyncStorage.getItem("userData");
if (userData) {
// parse converts a string to an object or array
const transformedData = JSON.parse(userData);
const { userEmail } = transformedData;
return userEmail;
}
};
const email = await getEmail();
// Give it some time to get the token and userId,
// because saveData needs them.
setTimeout(
async () => await dispatch(dataActions.saveData(email, +points)),
3000
);
await AsyncStorage.removeItem("savedPoints");
}
};
if (isConnected) getPoints();
You can set up a listener to listen for an internet connection. Don't use any logic in app.js, use it in a separate screen component.
constructor(props) {
super(props);
this.state = {
isConnected: false
};
}
componentDidMount() {
this.listenForInternetConnection = NetInfo.addEventListener(state => {
// your logic is here or setState
this.setState({
isConnected: state.isConnected
});
});
}
componentWillUnmount() {
this.listenForInternetConnection();
}
You can use JS EventListeners
window.addEventListener('load', () => {
navigator.onLine ? showStatus(true) : showStatus(false);
window.addEventListener('online', () => {
showStatus(true);
});
window.addEventListener('offline', () => {
showStatus(false);
});
});

How can I initialize in useState with the data from custom hooks?

I'm learning to React Hooks.
And I'm struggling initialize data that I fetched from a server using a custom hook.
I think I'm using hooks wrong.
My code is below.
const useFetchLocation = () => {
const [currentLocation, setCurrentLocation] = useState([]);
const getCurrentLocation = (ignore) => {
...
};
useEffect(() => {
let ignore = false;
getCurrentLocation(ignore);
return () => { ignore = true; }
}, []);
return {currentLocation};
};
const useFetch = (coords) => {
console.log(coords);
const [stores, setStores] = useState([]);
const fetchData = (coords, ignore) => {
axios.get(`${URL}`)
.then(res => {
if (!ignore) {
setStores(res.data.results);
}
})
.catch(e => {
console.log(e);
});
};
useEffect(() => {
let ignore = false;
fetchData(ignore);
return () => {
ignore = true;
};
}, [coords]);
return {stores};
}
const App = () => {
const {currentLocation} = useFetchLocation();
const {stores} = useFetch(currentLocation); // it doesn't know what currentLocation is.
...
Obviously, it doesn't work synchronously.
However, I believe there's the correct way to do so.
In this case, what should I do?
I would appreciate if you give me any ideas.
Thank you.
Not sure what all the ignore variables are about, but you can just check in your effect if coords is set. Only when coords is set you should make the axios request.
const useFetchLocation = () => {
// Start out with null instead of an empty array, this makes is easier to check later on
const [currentLocation, setCurrentLocation] = useState(null);
const getCurrentLocation = () => {
// Somehow figure out the current location and store it in the state
setTimeout(() => {
setCurrentLocation({ lat: 1, lng: 2 });
}, 500);
};
useEffect(() => {
getCurrentLocation();
}, []);
return { currentLocation };
};
const useFetch = coords => {
const [stores, setStores] = useState([]);
const fetchData = coords => {
console.log("make some HTTP request using coords:", coords);
setTimeout(() => {
console.log("pretending to receive data");
setStores([{ id: 1, name: "Store 1" }]);
}, 500);
};
useEffect(() => {
/*
* When the location is set from useFetchLocation the useFetch code is
* also triggered again. The first time coords is null so the fetchData code
* will not be executed. Then, when the coords is set to an actual object
* containing coordinates, the fetchData code will execute.
*/
if (coords) {
fetchData(coords);
}
}, [coords]);
return { stores };
};
function App() {
const { currentLocation } = useFetchLocation();
const { stores } = useFetch(currentLocation);
return (
<div className="App">
<ul>
{stores.map(store => (
<li key={store.id}>{store.name}</li>
))}
</ul>
</div>
);
}
Working sandbox (without the comments) https://codesandbox.io/embed/eager-elion-0ki0v

Resources