My Problem :
I expect my FirebaseProvider function to provide an object containing all functions, through the app. The problem is that all functions are well provided through my files, except my last new function : fetchTest.
Explainations :
If I click the TestPage.js button I get Uncaught TypeError: fetchTest is not a function.
I saw many posts on stackoverflow about this type of error, but none did help me. -> I think the original problem is the index.js is not called. The console.log("firebaseprovider") (in index.js) does not appear in console, yet the other files of the project in web-app/src/views/ have the same imports and exports than TestPage.
Since App.js code worked fine on all the other files, I don't know how console.log("firebaseprovider") is never displayed in the navigator console. (edit: no matter which page I go, this console.log never appears)
<FirebaseProvider> seems to not provide TestPage.js.
Do you have an idea ?
What I've tried :
placing a console.log in TestPage.js : it shows every function written in index.js but not fetchTest. It seems to not be properly exported through api object.
in TestPage.js trying console.log("api.fetchTest") : console displays undefined.
add a second testing function in index.js, whithout parameters, which just does console.log("test")
compare imports/exports and api declarations with other files in web-app/src/views/
create a handleSubmit() function in TestPage.js to not put the functions directly in return
delete node_modules and then yarn install
yarn workspace web-app build and then relaunch yarn workspace web-app start
(This is a Yarn Workspaces project containing a common/ and a web-app/ folders)
common/src/index.js:
import React, { createContext } from 'react';
import {FirebaseConfig} from 'config';
const FirebaseContext = createContext(null);
const FirebaseProvider = ({ children }) => {
console.log("firebaseprovider"); // is not displayed in the console
let firebase = { app: null, database: null, auth: null, storage:null }
if (!app.apps.length) { // I tried to comment out this line (and the '}') -> no difference
app.initializeApp(FirebaseConfig); // no difference when commented out
firebase = {
app: app,
database: app.database(),
auth: app.auth(),
storage: app.storage(),
// [ ... ] other lines of similar code
api : { // here are functions to import
fetchUser: () => (dispatch) => fetchUser()(dispatch)(firebase),
addProfile: (details) => (dispatch) => addProfile(userDetails)(dispatch)(firebase),
// [ ... ] other functions, properly exported and working in other files
// My function :
fetchTest: (testData) => (dispatch) => fetchTest(testData)(dispatch)(firebase),
}
}
}
return (
<FirebaseContext.Provider value={firebase}>
{children}
</FirebaseContext.Provider>
)
}
export { FirebaseContext, FirebaseProvider, store }
web-app/src/views/TestPage.js:
import React, { useContext } from "react";
import { useDispatch } from "react-redux";
import { FirebaseContext } from "common";
const TestPage.js = () => {
const { api } = useContext(FirebaseContext);
console.log(api); // Displays all functions in api object, but not fetchTest
const { fetchTest } = api;
const dispatch = useDispatch();
const testData = { validation: "pending" };
return <button onClick={ () => {
dispatch(fetchTest(testData)); // Tried with/without dispatch
alert("done");
}}>Test button</button>
}
export default TestPage;
web-app/src/App.js:
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
// ... import all pages
import { Provider } from 'react-redux';
import TestPage from './views/CreateSiteNeed'; // written same way for the other pages
import { store, FirebaseProvider } from 'common';
function App() {
return (
<Provider store={store}>
<FirebaseProvider>
<AuthLoading>
<Router history={hist}>
<Switch>
<ProtectedRoute exact component={MyProfile} path="/profile" />
<!-- [ ... ] more <ProtectedRoute /> lines, form imported Pages line 3. -->
<ProtectedRoute exact component={TestPage} path="/testpage" />
</Switch>
</Router>
</AuthLoading>
</FirebaseProvider>
</Provider>
);
}
export default App;
I hope some people will find this post helpful, thanks
Here was the problem :
Firstly :
I'm using Redux, so fetchTest() has its testActions.js and testReducer.js files, which are functionnal. But I did forget to update my store.js :
// [ ... ] import all reducers
import { testReducer as testData } from '../reducers/testReducer'; // was'nt imported
const reducers = combineReducers({
auth,
usersdata,
// [ ... ] other imported reducers
testData // My test reducer
}
// The rest is a classic store.js code
Secondly :
As I'm using Yarn Workspaces, I had to compile the code in common/dist/index.js to make it accessible through the whole entire code (even for local testing).
Here is the command to compile the code (-> to include all redux edits made above) and make it accessible to web-app workspace :
yarn workspace common build && yarn workspace web-app add common#1.0.0 --force
Explanations on the second part of the command (yarn workspace web-app add common#1.0.0 --force) :
The web-app/package.json file contains { "dependencies": { ... "common":"1.0.0" ... }}
Related
The Problem:
I'm building a blog with Next and sanity. When navigating to /blog, i'm encountering this error in the browser:
./sanity.js:2:0
Module not found: Can't resolve '#sanity/image-url'
1 | import { createCurrentUserHook, createClient } from "next-sanity";
> 2 | import imageUrlBuilder from "#sanity/image-url";
3 |
4 | export const config = {
5 | // Find your project ID and dataset in 'sanity.json' in your studio project.
Import trace for requested module:
./pages/blog.tsx
https://nextjs.org/docs/messages/module-not-found
The folder structure is:
root
-> components
-> pages
-> post
-> [slug].tsx
-> index.tsx
-> blog.tsx
-> sanity subfolder
-> public
-> styles
sanity.js (config file)
The sanity config file
I have a sanity config file, which exports some helper functions. One of which, is the imageUrlBuilder function, which i'm assuming the error is coming from. Here is my sanity config file: Note: this is pulled from sanity docs.
import { createCurrentUserHook, createClient } from "next-sanity";
import imageUrlBuilder from "#sanity/image-url";
export const config = {
// config info here
};
// Set up the client for fetching data in the getProps page functions.
export const sanityClient = createClient(config);
// Builder function to combo with urlFor function.
const builder = imageUrlBuilder(sanityClient);
// Helper function to generate urls from sanity photos.
export const urlFor = (source) => {
return builder.image(source);
};
The helper function was working in a previous version, and was able to pull images from sanity and display in the document. But i'm unsure why it's causing issues with page routing.
The blog page component:
import React from "react";
import BlogPreview from "../components/BlogPreview";
import { getAllPosts } from "../queries";
import { sanityClient } from "../sanity";
import { Post } from "../typings";
interface Props {
posts: [Post];
}
// required for server-side rendering. returns 'props' object from db.
export const getServerSideProps = async () => {
let query = getAllPosts;
const posts = await sanityClient.fetch(query);
return {
props: {
posts,
},
};
};
function blog({ posts }: Props) {
return (
<div>
<div className='md:grid md:grid-cols-2'>
{posts.map((post) => {
return (
<BlogPreview
key={post._id}
title={post.title}
description={post.description}
mainImage={post.mainImage}
slug={post.slug}
/>
);
})}
</div>
</div>
);
}
export default blog;
I've tried:
Logging sanity data to the console to check for config errors.
Googling the error: Module not found: Can't resolve '#sanity/image-url'
Conclusion
I'm unsure what the issue is, and how I can potentially solve it. Would love some ideas.
Thanks in advance
It sounds like you don't have the #sanity/image-url module installed in your project.
Run this in your project directory and you should be good to go!
npm install --save #sanity/image-url
I made one react app. My app works as expected. This app's target is practice AWS-COGNITO. For Cognito validation I am using amazon-cognito-identity-js package. I made one helper function where I validate the Congnito. and reuse it in different component. I split my Nav bar into two components. From Congnito current user I made one callback function and use it in useEffect, and dependencies put the callback function, by default getAuthenticatedUser is null. I add condition where it fetch the data, if getAuthenticatedUser then redirect to signin and signup page. I deployed my app to s3 bucket and this the link. This app runs first time, When I refresh it then got error: 404 Not Found. I really don't know what is the issue and somehow the path react path get disappear. I share my code in code-sandbox.
This is my conditional path
import React from "react";
import SigninLinks from './SigninLinks';
import SignoutLinks from './SignoutLinks';
import useHandlder from '../configHandler/useHandler';
const Nav = () => {
const { getAuthenticatedUser } = useHandlder();
const Links = getAuthenticatedUser() === null ? <SignoutLinks /> : <SigninLinks />
return (
<nav className="nav-wrapper grey darken-3">
<div className="container">
<h2 className="brand-logo">Logo</h2>
{
Links
}
</div>
</nav>
);
};
export default Nav;
This is my handler functions
import React, { useCallback, useEffect } from 'react';
import { CognitoUserPool } from 'amazon-cognito-identity-js';
const Pool_Data = {
UserPoolId: "us-east-1_9gLKIVCjP",
ClientId: "629n5o7ahjrpv6oau9reo669gv"
};
export default function useHandler() {
const userPool = new CognitoUserPool(Pool_Data)
const getAuthenticatedUser = useCallback(() => {
return userPool.getCurrentUser();
},
[],
);
useEffect(() => {
getAuthenticatedUser()
}, [getAuthenticatedUser])
const signOut = () => {
return userPool.getCurrentUser()?.signOut()
}
return {
userPool,
getAuthenticatedUser,
signOut
}
};
It's paths issue. You get 404 on /path not in root /. Check S3 settings for hosting static sites. On S3 make sure static website hosting is enabled:
You react app loads on /index.html JavaScript then redirects and takes over the path. You need S3 to resolve path to index.html, then it will work.
I have a reactjs app
In MyApp component I use an import at top like this:
import { ProvideAuth } from "util/auth.js";
Internally this file util/auth.js I have this code (I import another js file at top like this):
import analytics from "./analytics";
export function ProvideAuth({ children }) {
.....
}
How can I make this import analytics from "./analytics" dynamically depending on a cookie value?.
I made this code, but it doesn't work:
function loadLazyModule() {
console.log("loadLazyModule");
const _module = React.lazy(() =>
import("./analytics.js")
);
return _module;
}
// Provider hook that creates auth object and handles state
export function ProvideAuth({ children }) {
if (statisticsCookie == 'Y') {
console.log("statisticsCookie", statisticsCookie);
loadLazyModule();
}
.....
}
Finally my analytics.js has this code:
// Initialize analytics and plugins
// Documentation: https://getanalytics.io
const analytics = Analytics({
debug: process.env.NODE_ENV !== "production",
plugins: [
googleAnalyticsPlugin({
trackingId: process.env.NEXT_PUBLIC_GA_TRACKING_ID,
}),
],
});
....
export default analytics;
I need to this file import only if my cookie is enabled (has value 'Y'):
import analytics from "./analytics";
Help me please!
Thanks!
you can do it like this.
you can also use, .than().catch() function after that.
async function load() {
let say = await import('./say.js');
say.hi(); // Hello!
say.bye(); // Bye!
say.default(); // Module loaded (export default)!
}
or via import module
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error,e.g. if no such module>)
it's described here
https://javascript.info/modules-dynamic-imports
I am trying to follow this tutorial.
I'm currently stuck at the step which introduces react context to firebase.
This code block is the source of the current problem:
import Firebase, { FirebaseContext } from './components/firebase';
ReactDOM.render(
<FirebaseContext.Provider value={new Firebase()}>
<App />
</FirebaseContext.Provider>,
document.getElementById('root'),
);
serviceWorker.unregister();
When I try this, I get an error that says:
TypeError:_components_firebase__WEBPACK_IMPORTED_MODULE_5__.default is not a constructor
I have seen this post, which relates to Vue but says that the cause of an error with .default is not a constructor (not the rest of it), is because Firebase object should not be called with new keyword.
I tried removing new, but that generates an error message that says:
TypeError: Object(...) is not a function
I'm wondering if this has anything to do with the unusual way that the tutorial configures the app for firebase - which is with a class that uses a constructor (still don't understand why this is done this way):
class Firebase {
constructor() {
app.initializeApp(config);
this.auth = app.auth();
this.db = app.database();
}
export default Firebase;
Does anyone using Firebase with React know how to use the context API and if you do, have you found a way around this problem?
The firebase config setup files are:
index:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase.1';
export default Firebase;
export { FirebaseContext, withFirebase };
context:
import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default FirebaseContext;
NEXT ATTEMPT
I found this post, which looks like it might have been trying to follow the same tutorial.
That approach requires that I add back the auth method in the firebase.1.js config file so that it now looks like this:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
this.auth = app.auth();
// this.db = app.database();
// this.db = app.firebase.database()
this.db = app.firestore();
}
doCreateUserWithEmailAndPassword = (email, password) =>
this.auth.createUserWithEmailAndPassword(email, password);
}
Then, the submit handler in the form is like this:
handleCreate = values => {
values.preventDefault();
const { name, email, password } = this.state;
Firebase
.doCreateUserWithEmailAndPassword = (email, password) => {
return this.auth
.createUserWithEmailAndPassword(email, password)
.then((res) => {
Firebase.firestore().collection("users").doc(res.user.uid).set({
email: values.email,
name: values.name,
role: values.role,
createdAt: Firebase.FieldValue.serverTimestamp()
}).then(() => this.history.push(ROUTES.DASHBOARD));
})
.catch(err => {
console.log(err.message);
});
};
};
When I try this, I don't get any errors, but the form does not submit - it just hangs.
NEXT ATTEMPT
Since the FirebaseContext.Consumer includes a line with firebase in lowercase, I tried all of the same steps above, but replacing title case Firebase with lower case firebase. I also tried this.firebase (I don't know why) and this.props.firebase (I have seen other posts try that but still don't know why).
None of these approaches work either.
When I try to console.log(Firebase) above the FirebaseContext.Provider, I get this a big log with lots of drop down menus that starts with this:
FirebaseAppImpl {firebase_: {…}, isDeleted_: false, services_: {…},
tokenListeners_: Array(0), analyticsEventRequests_: Array(0), …}
INTERNAL: {analytics: {…}, getUid: ƒ, getToken: ƒ,
addAuthTokenListener: ƒ, removeAuthTokenListener: ƒ}
One of the drop down menus inside this log is labelled "options_" and includes my firebase app credentials.
I think this could be related to the problem in my recent other answer.
I managed to get new Firebase working by simplifying the import/export setup.
In the react app the imports are now:
import { FirebaseContext } from './components/context';
import Firebase from './components/firebase';
Those imports and the new work after I replaced the complicated "import and re-export" code in the components/firebase.js with simply the definition for the class Firebase from the tutorial.
After this another error Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app). pops up, but that could be because I didn't follow the whole tutorial and some configuration is missing.
Replicating everything you are dealing with is quite difficult without having the full source of your project.
Here is the test App.js I used after the npx create-react-app react-firebase-authentication and after installing firebase.
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { FirebaseContext } from './components/context';
import Firebase from './components/firebase';
function App() {
const foo = new Firebase()
return (
<div className="App">
... omitted ...
</div>
);
}
export default App;
I saw this answer which shows how to get react-hot-loader working with import() syntax, but in my case I don't know the filename until runtime.
Here's what I've got:
export default function(component, props, mountPoint) {
function render() {
import(`./containers/${component}`).then(({default: Component}) => {
ReactDOM.render(
<AppContainer>
<ErrorBoundary>
<Component {...props}/>
</ErrorBoundary>
</AppContainer>, document.getElementById(mountPoint || 'react-root'));
});
}
render();
if(module.hot) {
module.hot.accept('./containers', () => {
render();
});
}
}
The first load works fine, it's just the module.hot block that doesn't work. Chrome tells me:
Uncaught (in promise) Error: Cannot find module "./containers"
And my terminal tells me the same thing:
WARNING in ./node_modules/babel-loader/lib?{"cacheDirectory":"/usr/local/myproject/cache/babel","forceEnv":"development"}!./assets/scripts/app/react_loader.js
Module not found: Error: Can't resolve './containers' in '/usr/local/myproject/assets/scripts/app'
If I try to accept ./containers/${component} then I get a runtime error instead:
Ignored an update to unaccepted module ./assets/scripts/lib/components/bpm/MyClientProcessMenu.jsx -> ./assets/scripts/lib/components/bpm/MyClientProcessMenuLoader.jsx -> ./assets/scripts/app/containers/MyClientProcessMenuContainer.jsx -> ./assets/scripts/app/containers lazy recursive ^./.$ -> ./node_modules/babel-loader/lib/index.js?{"cacheDirectory":"/usr/local/myproject/cache/babel","forceEnv":"development"}!./assets/scripts/app/react_loader.js -> ./node_modules/bundle-loader/index.js!./assets/scripts/app/react_loader.js -> ./assets/scripts/app recursive ./node_modules/bundle-loader/index.js!./ ^./.$ -> ./assets/scripts/lib/webpack.js -> ./assets/main.js -> 0
And no update occurs.
How can I "accept" a dynamic component?
I do not think that this is currently supported without duplicating a code. As a workaround, you can create two files one would be used for production with dynamic import and the second one would be without dynamic import for development.
The file with dynamic import has to be included only in production. That's the reason for moving the environment logic into the different file (index.js)
index.js
// Neded because HMR doesn't work with dynamic import for languages
let app;
if (process.env.NODE_ENV === 'development') {
app = require('./development').default;
} else {
app = require('./production').default;
}
app(component);
client.js
export default function(Component) {
function render() {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>, document.getElementById('react-root'));
}
render();
if(module.hot) {
module.hot.accept('./containers', () => {
render();
});
}
}
production.js
import client from './client';
export default function (component) {
import(`./containers/${component}`).then(Component => {
client(Component)
});
}
development.js
import client from './client';
export default function (component) {
const Component = require(`./containers/${component}`);
client(Component);
}