Implement two Providers in React application - javascript

I am attempting to implement a Redux store into my react application. I am using Auth0 for Authentication and Authorization. I need to store data such as UserID and permissions into my store. Currently my index.js file is as follows:
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import { Auth0Provider } from "./react-auth0-spa";
import config from "./auth_config.json";
import history from "./utils/history";
import {createStore} from "redux";
import rootReducer from './redux/reducer';
import {Provider} from "react-redux";
//create Redux store
const store = createStore(rootReducer);
// A function that routes the user to the right place
// after login
const onRedirectCallback = appState => {
history.push(
appState && appState.targetUrl
? appState.targetUrl
: window.location.pathname
);
};
ReactDOM.render(
<Auth0Provider
domain={config.domain}
client_id={config.clientId}
redirect_uri={window.location.origin}
audience={config.audience}
onRedirectCallback={onRedirectCallback}
>
<App />
</Auth0Provider>,
document.getElementById("root")
);
Should the Provider for Redux wrap the Auth0 provider or should Auth0 wrap Redux?

It shouldn't matter. Everything nested inside of the two providers, regardless of which is wrapping the other, should have access to what they provide.

Related

how to use Vuex in Laravel + Vue 3 project

working with Laravel + Vue 3 project. I need work with Vuex in the project. I have configure My Vuex in store.js file as following
import { createApp } from 'vue'
import { createStore } from 'vuex'
const store = createStore({
/* state, actions, mutations */
state : {
counter : 1000
}
});
const app = createApp();
app.use(store);
app.mount("#app");
and My app.js file as following
import ViewUIPlus from 'view-ui-plus'
import 'view-ui-plus/dist/styles/viewuiplus.css'
import 'view-ui-plus/dist/styles/viewuiplus.css'
import common from './common'
import store from './store' //import store.js
createApp({
components: {
mainapp,
}
}).use(router).use(ViewUIPlus).mixin(common).mount('#app');
now I am unable to how to import store.js in to the app.js file. could you give some solution here
Important note: Vue core team members (including Vuex authors) highly recommend using Pinia instead of Vuex for new projects, on the very first page of Vuex docs.
You're currently creating two separate apps:
one in store.js (which has the store but nothing else)
one in app.js (which has everything but the store).
You probably want to add the store to the app in app.js, not to a separate app. You should export the store from store.js and import + use it into app.js:
store.js
export const store = createStore({
//...
})
app.js:
import { store } from './store'
const app = createApp({
//...
})
.use(router)
.use(store)
.use(ViewUIPlus)
.mixin(common)
.mount('#app')

Cannot access redux store in actions/api service (without connect() func)

I'm trying to fetch the token from my auth reducer in my app for making subsequent requests for more resources.
The problem is I can't access the store.getState() or store anywhere outside my components. Like actions/api service.
I remember earlier making an app where I was able to without any problems.
Here's a contrived example : https://stackblitz.com/edit/react-redux-app-1wxxab?file=index.js I've made a basic todo app and you can see in actions/index.js that when I console.log(store) I get undefined.
Update: I've updated the example to emphasise the problem, where I can't access it in a separate file api.js
Another Example: https://stackoverflow.com/a/43944684/1356046 they say it works like this but I'm not able to reproduce it.
Anyway to fix this and access the store state? Have tried everything since yesterday. Thanks.
Export store when you created it, then use it eg store.dispatch(action); or create api specific middleware
See What is the best way to access redux store outside a react component? for many examples
Update:
https://stackblitz.com/edit/react-redux-app-1mswrv
store.js:
import { configureStore } from "redux-starter-kit";
import rootReducer from './reducers'
export const store = configureStore({
reducer: rootReducer,
});
index.js:
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './components/App'
import { store } from "./store";
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
api.js:
import {store} from './store';
// Some promise which dispatches a fetch request after getting the token from the store
export const getSomething = () => {
console.log('store:', store);
return store;
}
Cloned your stackblitz and made the following changes:
In your api file do the following:
import store from './store';
Add a store.js with the content:
import { configureStore } from "redux-starter-kit";
import rootReducer from './reducers'
const store = configureStore({
reducer: rootReducer,
});
export default store;
And changed your index.js to:
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import App from './components/App'
import store from './store'
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
I would still opt for saving a token in local storage, if the user is logged in and opens another tab the user needs to log in again because the other tab has no access to the token, same when the user goes to another site and then back to your site.
If you are using redux-thunk and passing your api with withExtraArgument() to the thunk middleware passed to createStore() then you can use a lazy callback function to inject selectors for your API token (or whatever else you'd like) to a wrapped API helper function.
Personally, I prefer this approach as it decouples the api helper from redux. The API helper does not have to know about redux at all for this to work. Insread of imports, you simply inject the selector into the API helper, which then calls them when needed (long after the store is initialized).
api.js
// function accepting callback that returns a pretty
// standard post function
export const post = (getHeaders) => (url, body) => {
return fetch(url, {
method: 'POST',
headers: getHeaders(),
...
}
}
store.js
import * as api from './utils/api';
import { selectAuthHeaders } from './features/auth'
const store = createStore(
rootReducer,
initialState,
applyMiddleware(
thunk.withExtraArgument({
post: api.post(() => {
return selectAuthHeaders(store.getState());
}
})
)
)

How to use create-react-app bundle in plain javascript?

I want to build my react project into a bundle.js file and then use that bundle in a plain javascript file. This is to integrate the react application with another application that uses plain javascript
Do I need to eject my application and change the webpack config so that the index.js gets exported?
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import data from './mocks/data'
import { Provider } from 'react-redux';
import store from './redux/store'
function callback() {
return data;
}
function loadApp(root, callback) {
ReactDOM.render(<Provider store={store}><App getData={callback} /></Provider>, document.getElementById(root));
serviceWorker.unregister();
}
if (process.env.NODE_ENV == "development") {
loadApp('root', callback)
}
export default loadApp

Cannot read property 'getState' of undefined error

I am trying to add the react sticky header to my stepper.
but the problem is if I add inside my App.js its not rendering.
so I started debugging the App.js code.
if I give console inside my render method of App.js its not displaying console.log("App---->");
right now I am getting Cannot read property 'getState' of undefined error
can you tell me how to fix it.
so that in future I will fix it myself.
providing my code snippet and sandbox below
https://codesandbox.io/s/6zv5n0ro9z
App.js
import React from "react";
import { StickyContainer, Sticky } from "react-sticky";
// ...
class App extends React.Component {
render() {
console.log("App---->");
return (
<StickyContainer>
{/* Other elements can be in between `StickyContainer` and `Sticky`,
but certain styles can break the positioning logic used. */}
<Sticky>
{({
style,
// the following are also available but unused in this example
isSticky,
wasSticky,
distanceFromTop,
distanceFromBottom,
calculatedHeight
}) => <header style={style}>{/* ... */}</header>}
</Sticky>
{/* ... */}
</StickyContainer>
);
}
}
index.js
import React from "react";
//import ReactDOM from "react-dom";
import Demo from "./demo";
import App from "./components/App";
import { render } from "react-dom";
import { logger } from "redux-logger";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
//import reducer from "./reducers";
import thunk from "redux-thunk";
//const store = createStore(reducer, applyMiddleware(thunk, logger));
//ReactDOM.render(<Demo />, document.querySelector("#root"));
render(
// <Provider store={store}>
<Provider>
<App />
</Provider>,
document.getElementById("root")
);
You need to either pass a store to the Provider as Mark suggests, or if you have simplified your example to the point of not needing it, then remove the Provider element entirely so you are just rendering the App element. The current stack trace shows that the error is in Provider.
You also need to add:
export default App;
to the bottom of App.js.
You need to pass your store as props to the wrapping Provider
render(<Provider store={store} >
<App />
</Provider>,document.getElementById("root"));
If you're going to render a React-Redux <Provider>, you must create a Redux store and pass it as a prop named store. I see you've got those lines in there - you should uncomment them.
Chances are that you would have not set the store property correctly.
Make sure that store is imported this way.
import store from './store';
and not the below way
import {store} from './store';
<!-- begin snippet: js hide: false console: true babel: false -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
import store from './store';
Running code should look like below
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './routes/App';
import * as serviceWorker from './serviceWorker';
import { Provider } from "react-redux";
import store from './store';
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
enter code here
For anyone else stumbling on this, try to pull your <Provider> up a level and make use of your getters from a child.
Make sure you have imported import store from './redux/store' and pasing provider as <Provider store={store}> here I am emphasizing on `store' file and import must be small letter must not be camel or uppercase. This is what i have found during redux learning.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './routes/App';
import * as serviceWorker from './serviceWorker';
import { Provider } from "react-redux";
import store from './store';
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();

Promise Redux : TypeError: next is not a function

I have a little app running on React + Redux with redux-promise middleware in order to deal with promise API call. I would like to manage the state of each api call (loading, success & error). So, as the official documentation says I change the applyMiddleware argument.
import React from 'react';
import ReactDOM from 'react-dom';
import promiseMiddleware from 'redux-promise';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, browserHistory } from 'react-router';
import reducers from './reducers';
import routes from './routes';
const createStoreWithMiddleware = applyMiddleware(
promiseMiddleware({
promiseTypeSuffixes: ['LOADING', 'SUCCESS', 'ERROR'],
}),
)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory} routes={routes} />
</Provider>
, document.querySelector('.container'));
But when I change the appyMiddleware my app doesn't work anymore, I have this error showing on console:
TypeError: next is not a function
If I change back this line, everything works again as intended.
const createStoreWithMiddleware = applyMiddleware(promiseMiddleware)(createStore); // App works again
What's wrong?
Thank you,
I strongly believe that the way you create the store is incorrect.
In creating a store, there are 3 arguments,
createStore(reducer, preloadedState, enhancer) {...}
(1) reducer -> (required)
(2) preLoadedState -> (optional)
(3) enhancer -> (optional) // This is where your applyMiddleware should be passed. Hence, the minimal creation of a store is,
const store = createStore(() => {});
To answer your question, creating a store with a middleware should be,
const store = createStore(yourReducer, {}, applyMiddleware(promiseMiddleware))
or simply
const store = createStore(yourReducer, applyMiddleware(promiseMiddleware))
// This should also work because if the 2nd parameter is a function then it will be treated as the enhancer.

Categories