Could someone please explain what is going wrong in simple terms so I know how to fix this and can deal with it next time I encounter it.
I have looked through all related questions I could find on stackoverflow and haven't been able to fix it, if I have missed one that answers this then please link it.
I have had this error in the past but usually that was just because I had a typo (e.g. a capital instead of a lowercase) or did not import something correctly however that is not the case this time as far as I can tell.
FIRST CODE app.js
SECOND CODE interactions.js
Here is my code
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Navbar from './Navbar'
import Web3 from 'web3';
import { connect } from 'react-redux'
// import Token from '../abis/Token.json'
import {
loadWeb3,
loadAccount,
loadToken,
loadExchange
} from '../store/interactions'
class App extends Component {
componentWillMount() {
this.loadBlockchainData(this.props.dispatch)
}
async loadBlockchainData(dispatch) {
const web3 = loadWeb3(dispatch)
const network = await web3.eth.net.getNetworkType()
const networkId = await web3.eth.net.getId()
const accounts = await loadAccount(web3, dispatch) // <<--
const token = loadToken(web3, networkId, dispatch)
loadExchange(web3, networkId, dispatch)
}
// ......................
function mapStateToProps(state) {
return {
account: accountSelector(state)
}
}
export default connect(mapStateToProps)(App);
import Web3 from 'web3'
import {
web3Loaded,
web3AccountLoaded,
tokenLoaded,
exchangeLoaded
} from './actions'
import Token from '../abis/Token.json'
import Exchange from '../abis/Exchange.json'
export const loadWeb3 = (dispatch) => {
const web3 = new Web3(Web3.givenProvider || 'http://localhost:7545')
dispatch(web3Loaded(web3))
return web3
}
export const loadAccount = async (web3, dispatch) => {
const accounts = await web3.eth.getAccounts()
const account = accounts[0]
dispatch(web3AccountLoaded(account))
return account
}
export const loadToken = async (web3, networkId, dispatch) => {
try {
const token = new web3.eth.Contract(Token.abi, Token.networks[networkId].address) // new 이거 의존성(버전) 문제 이거 조심!!!!!
dispatch(tokenLoaded(token))
return token
} catch (error) {
window.alert('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
export const loadExchange = async (web3, networkId, dispatch) => {
try {
const exchange = new web3.eth.Contract(Exchange.abi, Exchange.networks[networkId].address)
dispatch(exchangeLoaded(exchange))
return exchange
} catch (error) {
window.alert('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
i don'k now why this happening to me
but please let me know this problem if you know this issue
The problem seems to be that you do not define or import the accountSelector function anywhere.
You usually define Redux selector functions in your reducer definition files: they take the current Redux store state as argument (and optionally the connected component props) and return the value to be used in your MapStateToProps object property.
Ex.
export const accountSelector = (state) => state.account
You can read more about selectors on the dedicated Redux resources page
replace this
function mapStateToProps(state) {
return {
account: accountSelector(state)
}
}
with this
function mapStateToProps(state) {
return {
account: state.accountSelector
}
}
you are passing complete state in variable instead of accessing.
for your reference, how to access please go through official documentation for your better understanding Redux
Related
as I continue to work on my issues I've got one that's kind of perplexing. my app has two JS files that interact with each other, but what's odd is it seems that then I call the function to get the data from firestore it seems that it wants to run it twice.
Here is the HomeScreen.js file that is suppoed to call UserInformation
import { Pressable, Text } from 'react-native';
import { useEffect, useId, useState } from 'react';
import { async } from '#firebase/util';
import { FlatList } from 'react-native-gesture-handler';
import {getStorage, ref, getDownloadURL} from 'firebase/storage';
//import the user infomration component
import UserInformation from '../components/UserInformation';
import ClubInformation from '../components/ClubInformation';
import AircraftInformation from '../components/AircraftInformation';
function HomeScreen() {
const userDetails = UserInformation();
const clubDetails = ClubInformation();
const aircraftDetails = AircraftInformation();
if (userDetails !== null) {
//console.log(userDetails)
//console.log(clubDetails)
//console.log(aircraftDetails)
}
if(!userDetails) {
return <Text>Loading...</Text>
}
if(!clubDetails) {
return <Text>Loading...</Text>
}
return <Text>Welcome {userDetails.first} {userDetails.last} {clubDetails.name}! This is a placeholder for future updates in the home screen</Text>
}
export default HomeScreen
the userDetails calls is below:
userInformation.js
import { useState, useEffect } from "react";
import { getAuth } from "firebase/auth";
import { doc, getDoc } from "firebase/firestore";
import { db } from '../components/FirebaseConfig';
export default function UserInformation() {
const [userDetails, setUserDetails] = useState(null);
useEffect(() => {
async function getUserDetails() {
const user = getAuth().currentUser;
const userRef = doc(db, "users", user.uid);
const docSnap = await getDoc(userRef);
if (docSnap.exists()) {
const data = docSnap.data();
setUserDetails(data);
} else {
console.log("No such User!");
}
}
getUserDetails();
}, []);
return userDetails;
}
Whenever I do a console log from the HomeScreen it seems to first return null, then it returns the data. Is there something I'm doing wrong here (I'm sure it is) or is it standard behavior? Thank you in advance
I tried to run this multiple ways but those other functions that i have that also query the db seem to do the same thing. I don't know if it's something up with my async
This is expected behavior when UserInformation function is working as a custom hook.
The first time when HomeScreen component was initialized/mounted, the default value userDetails is null.
After a few seconds, the app fetches data from Firestore and updates userDetails state value which trigger a second rerender.
Note: Recommended best practice is always prefixed custom hooks function name use[FUNCTION_NAME] like useUserInformation.
Your logic is completely wrong. You couldn't wait on referencing hook function.
Even you can use useEffect hook if you want to get valid response.
function HomeScreen() {
const userDetails = UserInformation();
const clubDetails = ClubInformation();
const aircraftDetails = AircraftInformation();
useEffect(()=>{
if (userDetails) {
console.log(userDetails)
}
}, [userDetails])
if(!userDetails) {
return <Text>Loading...</Text>
}
if(!clubDetails) {
return <Text>Loading...</Text>
}
return <Text>Welcome {userDetails.first} {userDetails.last} {clubDetails.name}! This is a placeholder for future updates in the home screen</Text>
}
As I said in my comment you don't need to create your custom hook functions. It's enough with normal functions it will work like this.
async function getUserDetails() {
const user = getAuth().currentUser;
const userRef = doc(db, "users", user.uid);
const docSnap = await getDoc(userRef);
if (docSnap.exists()) {
const data = docSnap.data();
return data;
} else {
console.log("No such User!");
return null
}
}
function HomeScreen() {
const [userDetails, setUserDetails] = useState(null)
useEffect(()=>{
getUserDetails().then(data=>{
if (data != null) {
setUserDetails(data)
}
})
}, [])
if (!userDetails) {
return <Text>Loading...</Text>
}
return <Text>Welcome {userDetails.first} {userDetails.last}</Text>
}
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>}
</>
);
}
I created a file which would contain helper functions for querying the database. My problem is that I have to get my access token through the Context API but I can't call the useContext hook outside of a functional component. I could place the functions inside one, but I don't need the component, it would be unused. What is the best practice here?
import React, { useContext } from "react";
import axios from "axios";
import { AuthContext } from "../../contexts/auth-context.js";
import { mongoQuery } from "../xhr/QueryMongo";
const { getAccessToken } = useContext(AuthContext);
export async function fetchUserData(userId) {
const sRealmApp = "...";
const CancelTokenLogin = axios.CancelToken;
const sourceLogin = CancelTokenLogin.source();
let token = await getAccessToken("users");
const userQuery = `query {user (query:{_id:"${userId}"}) {name, role, residence }}`;
let queryResult = await mongoQuery(token, sRealmApp, userQuery, sourceLogin);
if (queryResult.data.data !== null && queryResult.data.data.user !== null) {
return queryResult.data.data.user;
} else return false;
//other similar helper functions....
}
(Why I'm creating a new file: I'm refactoring my code because I have a file which has 400 lines of code, but it's not a big project. So I decided to extract code which connects to the database because it's not directly linked to the component.)
You can always provide the context as a parameter for your helper function.
helperFunction.js
fetchUserData(userId, token) {
... rest of code
}
Component.js
Then get the token from your component using useContext
import React, {useContext, useEffect} from 'react';
import context from 'location of context';
import fetchUserData from 'location of helper function';
const Component = () => {
const userId = 123; // Not sure where you are getting this, but for example.
const {getToken} = useContext(context);
useEffect(() => {
fetchUserData(userId, getToken());
}, []);
return (JSX)
};
Although, I don't think this is the best approach. I've done this before and it makes testing a nightmare. Creating a customHook would be a better approach imo.
how can I use UseContext to make this const '' data '' accessible throughout my project? I'm trying to implement but I can't. It doesn't have to be with UseContext, it was just a way that I researched
import api from '../../services/api';
import React, {useContext} from 'react';
export default async function getItems() {
try {
const data = await api.get("/list-results");
return data;
} catch (error) {
return error
}
}
First, create yourself a context:
const MyContext = React.createContext(defaultValue);
Then call your getItems() and store the result in a state and pass it to your context provider:
const [storedData, setStoredData] = useState<MyData | null>(null);
useEffect(() => {
getItems().then((data) => setStoredData(data));
}, []);
if (!storedData) return <div>Loading</div>;
return <MyContext.Provider value={}><MyApp/> </MyContext.Provider>;
Ideally do some more error handling in there.
And finally, get your context using useContext in a component somewhere in MyApp:
const data = useContext(MyContext);
Code is untested and should be seen as pseudo-code.
I started by following the answer in this StackOverflow Question
But I added a helper function I use which creates a new Axios instance with the auth token associated with the user.
Which looks a little like this:
import axios from "axios";
const mockAxios: jest.Mocked<typeof axios> = jest.createMockFromModule("axios");
// this is the key to fix the axios.create() undefined error!
mockAxios.create = jest.fn(() => {
return mockAxios;
});
export const createAuthenticatedInstance = () => {
return mockAxios.create();
};
export default mockAxios;
Why does mockAxios.create() return undefined?
While the object 'mockAxios' (and the create function) is defined. When I actually call create it returns undefined despite the function being declared.
I know that I can side-step the issue by just returning mockAxios against but I'd like to understand why it doesn't work in the first place. What I'd expect is to return a new instance, which would be identical to mockAxios but it just returns undefined.
If you're creating an auto-mock (within __mocks__) it's meant to be a mock of the module and any helper functions are not expected to be within the module, but probably somewhere else with your code
Exmaple:
src/axios.utils.ts (utility module which exports axios and the function)
import axios from "axios";
export const createAuthenticatedInstance = (
...args: Parameters<typeof axios.create>
) => {
return axios.create(...args);
};
export default axios;
src/__mocks__/axios.ts (the axios mock)
const axios: jest.Mocked<typeof import("axios").default> = jest.createMockFromModule(
"axios"
);
axios.create.mockReturnThis();
export default axios;
src/api.ts (api implementation that uses the axios.util)
import axios from "axios";
import { createAuthenticatedInstance } from "./axios.utils";
const client = createAuthenticatedInstance({
baseURL: "http://example.com:80/main",
});
export default {
makeSomeReq: () => client.get<string>("/path"),
};
src/api.spec.ts (the test)
import api from "./api";
import axios, { AxiosResponse } from "axios";
jest.mock("axios");
const { get } = axios as jest.Mocked<typeof import("axios").default>;
describe("api", () => {
it("should have created an axios instance", () => {
expect(axios.create).toHaveBeenCalledWith({
baseURL: "http://example.com:80/main",
});
});
})
working example