I have built authorization into my React App using passport.js, and I would like to, in my App.js file, fetch my authorization routes to see if a user is logged into the app, or if nobody is logged in.
To help with the question, I have shared a condensed version of my React App's App.js file, and Index.js file.
// App.js File
// Import React Libraries, Routes, Container Pages
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Route } from 'react-router-dom';
import { userActions } from './actions/auth/auth-actions.js';
import GameLanding from './containers/StatsPages/Game/GameLanding';
import AppFooter from './components/AppFooter';
// And Create The App
class App extends Component {
constructor(props, context) {
super(props, context);
}
componentDidMount() {
this.props.dispatch(userActions.authorize());
}
render() {
return (
<div>
<Route exact path='/stats/games' render={() => <GameLanding userInfo={this.props.userInfo} />} />
<AppFooter />
</div>
);
}
}
// export default App;
function mapStateToProps(reduxState) {
return {
userInfo: reduxState.authorizedReducer.userInfo,
authorized: reduxState.authorizedReducer.authorized,
loading: reduxState.authorizedReducer.loading
};
}
export default connect(mapStateToProps)(App);
... my entire App.js file has ~15 Routes components, and (part of) my goal with my App.js file is to fetch the authorized and userInfo props, and pass these to the components in the various routes. I showed an example where I pass the userInfo prop to the GameLanding component.
Here is how I have set up my Index.js file.
// Index.js
// Import Libraries
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
// Import CSS and the App
import App from './App';
import 'react-table/react-table.css';
import './index.css';
import './App.css';
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root'));
My current problem is as such: For some reason, fetching the userInfo and authorized props is breaking my app. I am unfortunately getting no error messages... rather, all of the react-router-dom Links in my app are simply not working... clicking them changes the url, but the pages of my app no longer change...
My questions are then, (a) am i allowed to fetch authorization data in App.js in the manner I am doing so (using connect, with mapStateToProps, etc.), or am I doing this all wrong?
Whether or not somebody is logged into my app is an app-wide thing, not a page-specific thing, and I figured for this reason (also to prevent having to fetch auth props in many many container pages) that App.js is the best place to grab these props.
Any thoughts on why my app is breaking, or how else my App.js file should look (I am ~99% sure my index.js is fine), would be greatly appreciated! Thanks!
Edit: For reference, doing the following: (i) importing userActions, (ii) calling userActions.authorize() in componentDidMount, (iii) including the mapStateToProps and connect on bottom of app, etc. works for loading the auth props in any of my container components. e.g. if i had this code in my GameLanding component, it doesnt break the react-router-dom Links app-wide in the same manner that it does when this code is in App.js. Hence the title of the question. Thanks!
1) Reason for app breaking:
I am assuming userInfo and authorized props will be undefined, as component renders initially before componentDidMount runs and you have not handled undefined props. You could also pass default props for these props.
2) Better structure for authorization
I am assuming you need to authenticate each route for authorization.
i) Create routes file and enter all routes for your app.
ii) <Route exact path='/stats/games' component={GameLanding} onEnter={reqAuth}/>
Inside reqAuth function you should check if the user is authorized for that route or not.
iii) Inside App component call action for fetching data, store in store and use GameLanding as child component and pass props only when they are defined.
That is not whole code, but should give you gist.
Happy Coding!!!
Related
I have a NextJS application where I have a home page (index.js) and two other pages About(about.js) & Contact Us(contact.js).
I have created a BaseLayour.js file with is wrapping NextJS's MyApp component in _app.js file.
import React from "react";
import BaseLayout from "../layouts/BaseLayout";
function MyApp(props) {
const { Component, pageProps } = props;
return (
<BaseLayout>
<Component {...pageProps} />
</BaseLayout>
);
}
export default MyApp;
This BaseLayout component looks like this -
import React from "react";
import SEO from "../components/SEO";
import Header from "../components/Header";
import Footer from "../components/Footer";
function BaseLayout(props) {
const { children } = props;
return (
<div>
<SEO />
<Header />
{children}
<Footer />
</div>
);
}
export default BaseLayout;
As you can see above in the BaseLayout file, there is an SEO component (React). It contains some common metadata for all the pages. I have an API(api/getmetadata/) that delivers all the metadata in JSON format.
This metadata is supposed to load on the server-side so that the page will be optimized for SEO.
How can we call the API in order to retrieve the data on each request but only on the server-side?
What I have tried till now -
Tried calling API in the SEO component itself, but it is not running on the server-side as it is just a React component.
Tried creating a React context, and called the API from SEO/BaseLayout components, the API call is still not being made from the server-side.
Tried using getServerSideProps in the index.js page to call the API and retrieve the data, which worked perfectly, but the problem is we need to share the data between all the pages, not just the index.js home page.
Any help will be appreciated, If we can somehow make the API call and retrieve the data in the SEO component, it will solve our problem.
Thank you in advance guys.
I'm building an Express-React-Node app that I want to deploy on Google App Engine.
As I'm following several tutorials I've encountered these two apps architecture:
https://github.com/BalasubramaniM/react-nodejs-passport-app/tree/master/src
and
https://hackernoon.com/m-e-r-n-stack-application-using-passport-for-authentication-920b1140a134
I'd like to understand the differences.
The first one is only one app with Webpackand Babel.
On the client-side, I have a App.jsx file and Index.html file.
This is the App.jsx file:
import React from 'react';
const App = () => (
<div className='app'>This is a React app</div>
);
export default App;
And this is the html file:
<!DOCTYPE html>
<html>
<head>
<title>A Web App</title>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="./bundle.js"></script>
</head>
<body>
<div id="app">This is an Express App</div>
<script>
ReactDOM.render(
React.createElement(App.default),
document.getElementById('app')
);
</script>
</body>
</html>
The second one comes with a client app and a server app.
There is a index.jss file with the following code :
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import { Route, Switch } from "react-router-dom";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route path="/" component={App} />
</Switch>
</BrowserRouter>,
document.getElementById("root")
);
registerServiceWorker();
and a App.js file with the following code:
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import queryString from "query-string";
class App extends Component {
componentWillMount() {
var query = queryString.parse(this.props.location.search);
if (query.token) {
window.localStorage.setItem("jwt", query.token);
this.props.history.push("/");
}
}
render() {
return (
<div className="App">
//some stuff here
</div>
);
}
}
export default App;
There is nothing related to react in the html file.
I kind of understand that with the first project the rendering part is mixed within the html file but I'm not really able to understand the differences and does things articulate in one app and the other.
The 2nd one appears to be using the create-react-app engine to generate the scaffolding and starter files. The 2nd example incorporates JWT user authentication that gets stored in local storage whereas the first does not appear to do so. Additionally, the 2nd example leverages React Router which allows you to build a single-page web application with navigation without the page refreshing as the user navigates. React Router uses component structure to call components, which display the appropriate information and allows you to add routes rapidly to build out the navigation. That is how the App component is being rendered within the imported Route component prop in index.jss. And if someone adds another Route with another path containing another component prop like this:
<Route path="/another-path" component={SubComponent} />
you could then access that component by traveling to baseURL/another-path
Token authentication and the use of React-Router are the primary differences between these two projects.
There are no differences. Both versions will call ReactDOM.render with an App element.
If you compile the second version using webpack, webpack will bundle all files together and will produce the same code as your first, partly manual solution.
i was trying to migrate react-redux v5.X.X to v6.0.0 and there dosent seem to be any documentation for it.
i am using following versions :
"react": "^16.4.2"
"redux": "^4.0.0"
"react-redux": "^6.0.0"
the official change log says.
Passing store as a prop to a connected component is no longer supported. Instead, you may pass a custom context={MyContext} prop to both and . You may also pass {context : MyContext} as an option to connect.
link is here
here is my root index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { configureStore, history } from './Store';
import App from './App.hot';
import 'antd/dist/antd.min.css';
const reduxStore = configureStore();
ReactDOM.render(<App store={reduxStore} history={history} />, document.getElementById('root'));
here is my app.jsx (root component)
import React from 'react';
import PropTypes from 'prop-types';
import { Provider, connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { ConnectedRouter } from 'connected-react-router';
import Layout from './Layout';
class App extends React.Component {
static propTypes = {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
};
render() {
const { store, profile, history } = this.props;
return (
<main className="app-wrapper">
// what i understand from change log is this part
// i need to pass context instead of store as props.
<Provider store={store}>
<ConnectedRouter history={history}>
<Layout user={profile} />
</ConnectedRouter>
</Provider>
</main>
);
}
}
function mapStateToProps(store) {
return {
...
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
...
}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
as per change log i created context and passed it down to the provider
const storeContext = React.createContext(reduxStore);
here is my render function after that change
render() {
const { store, profile, history } = this.props;
return (
<main className="app-wrapper">
<Provider context={storeContext}>
<ConnectedRouter history={history}>
<Layout user={profile} />
</ConnectedRouter>
</Provider>
</main>
);
}
passing store as props to provider gives following error
Passing redux store in props has been removed and does not do anything. To use a custom Redux store for specific components, create a custom React context with React.createContext(), and pass the context object to React-Redux's Provider and specific components like: . You may also pass a {context : MyContext} option to connect
and passing as context gives following error
Could not find "store" in the context of "Connect(App)". Either wrap the root component in a , or pass a custom React context provider to and the corresponding React context consumer to Connect(App) in connect options.
i did not find any documentation expect this redux history document here it tells all the problems and solutions for the problem in react-redux and how the context api fixed it. but i am not sure how to actually implement it in real project.
did anyone face the same issue ? or can you please tell me how exactly to implement this change.
thanks
I was able to solve the problem by actually listening to what the error message said.
there were two problems with my code
i was passing store as props to my <App /> component. which is why the first warning/error message was comming.
Passing redux store in props has been removed and does not do anything. To use a custom Redux store for specific components, create a custom React context with React.createContext(), and pass the context object to React-Redux's Provider and specific components like: . You may also pass a {context : MyContext} option to connect
to fix this simply dont pass whole redux store as props to any component
my Provider from react-redux was not the root component. the error message said
Could not find "store" in the context of "Connect(App)". Either wrap
the root component in a Provider , or pass a custom React context provider to
and the corresponding React context consumer to Connect(App) in
connect options
so i followed the second wanring in the sentence
Either wrap the root component in a Provider , or pass a custom React context
so i wrapped my main root in provider. and things started working well.
ReactDOM.render(
<Provider store={reduxStore}>
<App />
</Provider>, document.getElementById('root'),
);
I had the same problem and this is how i solved it.
const MyContext = React.createContext();
class App extends Component {
render() {
return (
<Provider store = {store} context={MyContext}>
<BrowserRouter>
<div>
<Main context={MyContext}/>
</div>
</BrowserRouter>
</Provider>
);
}
}
Most of the tutorials I am seeing use a express.js file to route all get and post requests. I am using a React component using react-router-dom, do I need to use express? If yes, what is the best way to do so? Here is what my app is looking like following along 1/4 of this tutorial so far: https://www.youtube.com/watch?v=WDrU305J1yw&t=1693s
The mongoose code is probably misplaced and breaks the app.
import React, { Component } from 'react';
import { Route } from 'react-router-dom';
import mongoose from 'mongoose';
import '../styles/App.css';
import Input from './Input';
mongoose.connect(
'mongodb://admin-01:PW#node-log-shard-00-00-ecvwz.mongodb.net:27017,node-shot-log-shard-00-01-ecvwz.mongodb.net:27017,node-shot-log-shard-00-02-ecvwz.mongodb.net:27017/test?ssl=true&replicaSet=node-shot-log-shard-0&authSource=admin&retryWrites=true',
{
useMongoClient: true
}
);
class App extends Component {
render() {
return (
<div>
<div>
<Route exact path='/' component={ Input } />
</div>
</div>
);
}
}
export default App;
The best and correct way to do this is to have a backend server in whatever language you prefer(javascript, java, etc.) and connect this server with your database. Then in your react application when you need data from your database you will make a request to the server and the server will retrieve the data and them back to your react application.
My React Native app has several conditions in which it needs to handle deep links when the user clicks on a link for an invite. My intent was to setup the Link listeners in the main app.js file and when a deep link is detected I need to pass the data into the Splash view to determine several factors before adding the user to the group they are invited to.
I am using React Navigation. I initially tried to use redux by updating the store with the url data but ran into timing issues as the Splash page was loading before redux was updated. So I have attempted to create an HOC wrapper for the Navigator as follows:
HOC Linker:
import * as React from "react";
const Linker = (Component) => {
return ({ children, ...props }) => {
return (
<Component { ...props }>
{ children }
</Component>
);
}
};
export default Linker;
In my App JS file I import the Linker and wrap the main navigator with the HOC component. I then add a prop that is updated when React Native Linking method detects a deep link. It updates state with the parameters.
App JS:
import Navigator from './ui/navigation/navigator';
const LinkerWrapper = Linker(Navigator);
render() {
return (
<LinkerWrapper linking={this.state.url} />
);
}
My Navigator file looks as follows:
Navigator:
import { createSwitchNavigator } from 'react-navigation';
import Splash from '../screens/splash/splash';
import AuthStack from './auth';
import AppStack from './app';
const Navigator = createSwitchNavigator({
Loading: Splash,
Auth: AuthStack,
App: AppStack
});
export default Navigator;
When I click on a deep link the app opens as expected, I parse the url and prep the data object, state is updated and the splash page is re rendered as expected, the props are passed through the HOC, but when the componentWillReceiveProps method is ran in the Splash page I do not see any props from the linking prop.
I have tried many different things. I am really new to react so I know I am probably doing something fundamentally wrong. I am guessing I am missing something with React Navigation. One of the things I tried was to change the screen value to a function passing in the props. I was hoping that would magically make the linking prop appear in the Splash page props. Below was my attempt:
import React from 'react';
import { createSwitchNavigator } from 'react-navigation';
import Splash from '../screens/splash/splash';
import AuthStack from './auth';
import AppStack from './app';
const Navigator = createSwitchNavigator({
Loading: {
screen: props => <Splash { ...props }/>
},
Auth: AuthStack,
App: AppStack
});
export default Navigator;
Unfortunately that didn't work. Any assistance would be appreciated.
Thanks.