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
Related
I am trying to split a monolithic React application into micro-frontends using Webpack Module Federation
The application relies on Context objects that are provided by the Host application. The context works as expected inside of the Host application, but not in the Remote application.
My code looks like this:
Host Application
Context and Context provider:
// TestContext.js
import React from 'libs/react';
export const TestContext = React.createContext("Not Initialized :(");
// LocalSample.js
import React from 'libs/react';
import { TestContext } from './TestContext';
export default function () {
const context = React.useContext(TestContext);
return <div>Local: {context}</div>
}
// App.js
import React, { Suspense } from 'libs/react';
import { TestContext } from './TestContext';
import RemoteSample from 'remote1/RemoteSample';
import LocalSample from './LocalSample';
export default function () {
return (
<TestContext.Provider value="Initialized :)">
<LocalSample />
<Suspense fallback={'loading...'}>
<RemoteSample />
</Suspense>
</TestContext.Provider>
);
};
Remote Application
// RemoteSample.js
import React from 'libs/react';
import { TestContext } from 'host/TestContext';
export default function () {
const context = React.useContext(TestContext);
return <div>Remote: {context}</div>
}
Sample code is also available at https://github.com/christianheld/module-federation-context-repro
The output of the application is:
Local: Initialized :)
Remote: Not Initialized :(
How can I share the context value from Host to the Remote application?
The trick is to put your contexts in into the shared object in the Module Federation configuration.
In my application this looks like:
shared: {
"./src/MyContext": {}
}
I found the workaround in the following video: https://www.youtube.com/watch?v=-LNcpralkjM&t=540
Please watch the video for the explanation.
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 React App, that talks to several REST APIs.
I have refactored my app from redux-thunks to use react-query for the business logic of calling the APIs.
Watching videos on react-query, it was advised to abstract this into a custom hook.
So, for example:
//
// useTodos.js
import { useQuery } from 'react-query';
import { TodoApi } from 'my-api-lib';
import config from '../config';
const todoApi = new TodoApi(config.TODO_API_BASE_URL);
const useTodos = (params) =>
useQuery(
[todo, params],
() => todoApi.fetchTodos(params)
);
I have another App where I could use these hooks to also talk to the REST APIs. So I'd like to move the hooks into a common library. But the config is provided by the client. How do I get the config (TODO_BASE_API_URI) or even the "todoApi" instance, to the custom hook from the client?
In Redux I essentially dependency-injected the TodoApi instance at startup with "thunk with extra argument"
Is there a "hooky" way to get the global config to my custom hook?
The library (I assume it's my-api-lib) should export a function that expects the url (or any other config), and returns the useTodoApi hook.
In your common library:
import { useQuery } from 'react-query';
import { TodoApi } from './TodoApi';
export const createUseTodoApi = url => {
const todoApi = new TodoApi(url);
return params =>
useQuery(
[todo, params],
() => todoApi.fetchTodos(params)
);
}
In your apps:
import { createTodoApi } from 'my-api-lib';
import config from '../config';
export const useTodoApi = createUseTodoApi(config.TODO_API_BASE_URL);
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" ... }}
I want to authenticate users w/ Twitter in my React Native app. I'm using the react-native-oauth library https://github.com/fullstackreact/react-native-oauth
I just want to make sure I'm going about this in the most effective way.
First things first I add firebase to my app in a config/constants file
import firebase from 'firebase'
firebase.initializeApp({
apiKey: "MY-API-KEY",
authDomain: "MY-AUTH-DOMAIN",
databaseURL: "MY-DATABASE-URL",
storageBucket: "MY-STORAGE-BUCKET",
messagingSenderId: "MY-MESSAGING-ID"
});
const ref = firebase.database().ref()
const firebaseAuth = firebase.auth()
export { ref, firebaseAuth }
Then I install the react-native-oauth library
Now, in my redux/authenticationI would probably do something like this where I eventually dispatch an action that saves the response object in my redux authentication state to use later.
import OAuthManager from 'react-native-oauth';
const manager = new OAuthManager('Nimbus') // I'm sort of confused on what the name of the app should be. Is it just the name of the app when I ran react-native init? Or something else?
export default function handleAuthWithFirebase () {
// Some redux thunk
return function (dispatch, getState) {
dispatch(authenticating());
manager.configure({
twitter: {
consumer_key: 'SOME_CONSUMER_KEY',
consumer_secret: 'SOME_CONSUMER_SECRET'
},
});
manager.authorize('twitter', {scopes: 'profile email'})
.then(resp => dispatch(getProfile(resp))) // Save response object
.catch(err => console.log('There was an error'));
// Do some other stuff like pushing a new route, etc.
}
}
Then finally, in SplashContainer.js I would add this to the handleSignIn method (ultimately called by the presentational component).
import React, { PropTypes, Component } from 'react'
import { View, Text } from 'react-native'
// Import function
import { handleAuthWithFirebase } from '~/redux/modules/authentication'
import { Splash } from '~/components'
export default class SplashContainer extends Component {
handleSignIn = () => {
// Sign in user with Twitter
handleAuthWithFirebase.bind(this);
}
render () {
return (
<Splash handleSignIn={this.handleSignIn}/>
)
}
}
Sorry, I know it was sort of a lot but just want to make sure I'm implementing this correctly. Any suggestions to improve the flow would be appreciated. Thanks!
can you check authenticate twitter with this package
https://github.com/GoldenOwlAsia/react-native-twitter-signin ?