I want to integrate Shared code between React Native and React JS so I create one module which is uploaded on Gitlab and I gave path to my React JS project as below. First of all refer my project structure
In gitmodule it is like below image
In My App.js file i want to access service--> api.ts file so I gave path to my App.js file as below
import {getUserData} from '../src/rn_sharecodecommon/Service/api'
const { isLoading, data, message, getUser } = getUserData()
useEffect(()=>{
getUser('users')
},[])
and My Service/api.ts file code as below
import { useState } from "react";
import axios from "axios";
export const getUserData = () => {
const [isLoading, setIsLoading] = useState(false);
const [message, setMessage] = useState('');
const [data, setData] = useState({});
const getUser = async (url) => {
console.log("URL-->", url);
let res;
try {
console.log("URL--> 1");
setIsLoading(true);
axios.get('https://api.github.com/'+url).then((response) => {
res = response.data;
setIsLoading(false);
setData(response.data);
console.log("API lOfi",response.data);
});
} catch (error) {
console.log("URL--> 2");
setIsLoading(false);
setMessage(error);
}
};
return {
isLoading,
message,
data,
getUser,
};
}
When i run above code in React JS it is showing me error like below
Can't resolve '../src/rn_sharecodecommon/Service/api' in '/Volumes/Data/WebProject/SSCode/sharecode/src'
Any Idea how can i solve this error?
I just resolved by make small change in import as below
import { getUserData } from './rn_sharecodecommon/Service/api.ts'
Related
here's the jist of where I'm stuck (or just read the title for my question).
I have a firebase.js file where I have functions to authenticate. signinGithub, signinGoogle, signinEmail and so forth. The Firebase Auth business logic is in these functions.
I am showing errors with console.log or alert from these functions. The functions are imported into a Component and I don't know how to capture the functions result into the component by somehow setting state from this out-of-component function file.
Here's a basic example:
firebase.js
...
const signInWithGitHub = async () => {
try {
const res = await signInWithPopup(auth, githubProvider)
const user = res.user
} catch (err) {
alert(err) // ** I want to pass "err" from here to Login
// ** component by updating Logins state for a message
}
}
export {signinWithGitHub}
...
Login.jsx
import React, { useEffect, useState } from "react"
import { useAuthState } from "react-firebase-hooks/auth"
import {
auth,
signInWithGitHub
} from "../lib/firebase"
function Login() {
const [user, loading, error] = useAuthState(auth)
render(
{* Below is the method call from the imported custom firebase function *}
<button onClick={signInWithGitHub}>
Login with GitHub
</button>
)
}
...
I was thinking something like this but I can't fully resolve it in my mind:
Set state in Login.js const [message, setMessage] = useState('')
When the imported signinWithGitHub has an error message --
I'm stuck figuring out how to apply to function message to the state, any ideas?
You can create a custom function inside your Login. jsx file to call the original signInWithGitHub method with a try catch block. And more importantly, you should not use render inside a functional component. Use return to render the JSX in DOM.
firebase.js
export const signInWithGitHub = async () => {
try {
const res = await signInWithPopup(auth, githubProvider);
const user = res.user;
} catch (err) {
throw new Error(err?.message || "Unable to sign in with GitHub");
}
};
Login.jsx
import React, { useEffect, useState } from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { auth, signInWithGitHub } from "../lib/firebase";
function Login() {
const [user, loading, error] = useAuthState(auth);
const [errorMessage, setErrorMessage] = useState("");
const onLogin = async () => {
try {
await signInWithGitHub();
} catch (err) {
setErrorMessage(err);
}
};
return (
<>
<button onClick={onLogin}>Login with GitHub</button>
{!!errorMessage && <h5>{errorMessage}</h5>}
</>
);
}
In a react app, when creating a component, I use useEffect to handle a HTTP request via a custom hook (which fetch via a useCallback). Then, to parse the parameters for the request, I have a layer for services which return the expected values.
As a result, this workflow keeps re-rendering in a loop and the apps gets stacked.
Component:
import React, { Fragment, useContext, useEffect, useState } from 'react';
import { NavLink } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { getProject } from '../../../services/Project.service';
import { AuthContext } from '../../../shared/context/auth.context';
import { NavOptions } from '../../../shared/constants/NavOptions';
import { useHttpClient } from '../../../shared/hooks/http.hook';
import SideNavigation from '../../../shared/components/Navigation/SideNavigation/SideNavigation';
import NavLinks from '../../../shared/components/Navigation/NavLinks/NavLinks';
import './Dashboard.css';
const Dashboard = (props) => {
console.log('Dashboard...');
const { isLoading, error, sendRequest, clearError } = useHttpClient();
const [project, setProject] = useState();
const auth = useContext(AuthContext);
const projectId = useParams().projectId;
const getProject = async () => {
console.log('getProject...');
console.log('auth', auth.token);
const response = await sendRequest(getProject(projectId, auth.token));
if (response.status === 201) {
const responseData = await response.json();
console.log('project:', responseData);
setProject(responseData);
} else {
console.log('getting buildings failed!');
const error = await response.json();
}
};
useEffect(() => {
projectId && getProject();
}, []);
const { t, i18n } = useTranslation();
let content = (
<div className="bim-y-dashboard">
.
.
.
</div>
);
return (
<Fragment>
<SideNavigation>
<NavLinks options={NavOptions.PROJECT} projectId />
</SideNavigation>
<MainContent>{content}</MainContent>
</Fragment>
);
};
export default Dashboard;
Custom hook:
export const useHttpClient = () => {
const auth = useContext(AuthContext);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
const activeHttpRequests = useRef([]);
const sendRequest = useCallback(
async (url, method = 'GET', body = null, headers = {}) => {
console.log('sendRequest...');
console.log('url', url);
console.log('method', method);
console.log('body', body);
console.log('headers', headers);
},[]);
const clearError = () => {
setError(null);
};
useEffect(() => {
return () => {
activeHttpRequests.current.forEach(abortCtrl => abortCtrl.abort());
};
}, []);
return { isLoading, error, sendRequest, clearError };
};
Service:
export const getProject = (projectId, token) => {
console.log('getProject...');
return (`/projects/id/${projectId}`, 'GET', null, {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token,
});
}
What am I missing to avoid this constant re-rendering?
Thanks in advance.
I have the feeling your issue is in code you have not shared, as the above looks legit.
Things you can try:
Comment out const auth = useContext(AuthContext); in your custom hook to make sure the culprit is not in your context
Make sure const response = await sendRequest(..) returns what you are expecting
Add a new hook, something like const [data, setData] = useState(null), then after you get a response, set it in your hook setData(response)
Finally, in your useEffect, update your condition as projectId && !data && getProject();
That will ensure your re rendering issue is neither on your auth context nor in your fetch request.
Hope that helps; if not, please update the question with the full code of your component and I'll take a second look :)
RESOLVED:
Found this post: Link
It explains that because of sendRequest method, it keeps re-rendering.
While trying to use TMDB API in my project I ran into an issue that I am unable to figure out. I use copies of the same code as shown below in two different files and functions - one works, and the other one returned undefined for some reason. Can you please point out what I am not doing right, I need fresh new eyes on this. Thank you
import Head from 'next/head';
import React from 'react';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import styles from '../styles/Home.module.css';
export const getServerSideProps = async () => {
const movieApi = process.env.TMDB_API_KEY;
const res = await fetch(`https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${movieApi}&page=1`);
const movie_data = await res.json();
return {
props: {
movies : movie_data
},
}
}
const Form = ({movies}) => {
console.log(movies); //returns "Undefined"
const [search, Setsearch] = useState("");
//Handle input value
const getLocation = async (e) => {
// console.log(e.target.value)
e.preventDefault();
}
//Handle Submit
const handleSubmit = (event) =>{
// console.log("clicked")
event.preventDefault();
}
export const getServerSideProps = async () => {
const movieApi = process.env.TMDB_API_KEY;
const res = await fetch(`https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=${movieApi}&page=1`);
const movie_data = await res.json();
return {
props: {
movies : movie_data
},
}
}
export default function Home({movies}) {
console.log(movies); //works perdectly
const [session, loading] = useSession();
const tmdbMpviesResults = movies.results
As per your comment, <Form /> is not a page. Exactly that is your problem:
getServerSideProps can only be exported from a page. You can’t export it from non-page files.
My useEffect hook dont seem to be running the block of code within its scope. Not exactly sure why, when i debug it the useEffect hook gets hit but the code within it never runs. I have placed a break point and it never lands on it.
import {useState, useEffect} from "react";
const useApiResult = (request) => {
const [results, setResults] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
loadData(request);
}, [request]);
const loadData = async (request) => {
console.log(request)
try
{
const response = await fetch(request);
if(response.ok) {
setResults(await response.json());
setError(null);
} else {
setError(await response.text());
}
}
catch (err) {
setError(err);
}
}
return [results, error];
};
export default useApiResult;
Where I call useApiResult
import { useMemo } from 'react';
import { getPokemons } from '../requests';
import useApiResult from '../customHooks/useApiResults';
const usePokemons = () => {
const request = useMemo(() => getPokemons(), []);
return useApiResult(request);
}
export default usePokemons;
getpokemons.js
export const BASE_URL = "https://pokeapi.co/api/v2";
const createUrl = (base, path) => `${base}${path}`;
export const getPokemons = () => [
createUrl(BASE_URL, "/pokemon?offset=300&limit=10"),
{
method: "GET",
}
];
My steps to catch issue:
When I looked in your sandbox I noticed error: results is null
I also found const [results, error] = usePokemons(); in PokemonList component, so I thought that this error is not necessary, I just removed it. Because you never used it in component.
I still got results is null I just add condition render via &&. It looks like:
results &&
results.map((key, i) => (
I got new error: results.map is not a function. It means that results is not array. When I saw at results I noticed that it has inside array with the same name. So I just add resuts after a dot.
results &&
results.results.map((key, i) => (
Here we go:)
Recently am learning React hooks and am now doing a search app which have to call API then return the list movies correspond to what i type in the search box.
My code here:
useFetch.js
import { useState, useEffect } from 'react'
export const useFetch = (url, initialState) => {
const [data, setData] = useState(initialState)
const [loading, setLoading] = useState(true)
useEffect(() => {
async function fetchMovies() {
const response = await fetch(url)
const data = await response.json()
setData(data.Search)
setLoading(false)
}
fetchMovies()
}, [url])
return { data, loading }
}
App.js
import React, { useState } from 'react'
import Search from './components/Search'
import Result from './components/Result'
import Loading from './components/Loading'
import { useFetch } from './utils/useFetch'
export default function App() {
const [key, setKey] = useState('Iron man')
const onSearch = (key) => {
setKey(key)
}
const {data, loading} = useFetch(`https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`)
return (
<>
<Search handleSearch={onSearch}/>
<Loading isLoading={loading} />
<Result movies={data}/>
</>
)
}
As far as i understand after clicking button search function call API will be fired and return the result as expect. I can't put
const {data, loading} = useFetch(`https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`)
inside onSearch function. Follow the code function call API is automatically called whenever the app start and return undefined as result.
Can anyone help me out and explain why?
You are correct in your understanding of how hooks can only be called at the top level in a react component. Make the following changes and the API won't get called the first time around but will get called subsequently.
Use url state variable and extract generateUrl logic outside the component:
function generateUrl(key) {
return `https://www.omdbapi.com/?s=${key}&apikey=${API_KEY}`
}
function MyComponent() {
const [url, setUrl] = React.useState('');
//...
}
Check for url presence in useFetch hook by wrapping fetchMovies() call in an if condition. This way, API won't trigger since default value of url is empty.
import { useState, useEffect } from 'react'
export const useFetch = (url, initialState) => {
const [data, setData] = useState(initialState)
const [loading, setLoading] = useState(true)
useEffect(() => {
async function fetchMovies() {
const response = await fetch(url)
const data = await response.json()
setData(data.Search)
setLoading(false)
}
if(url) {
fetchMovies()
}
}, [url])
return { data, loading }
}
Finally, modify onSearch
const onSearch = (key) => {
setUrl(generateUrl(key))
}
Perhaps you could expose setUrl through something like:
return { data, loading, onSearch: (key) => setUrl(generateUrl(key)) }