Props passed to the enclosed component of withAuthenticator HOC is empty - reactjs

I am expecting props.onStateChange but props is empty object.
Props passed to the enclosed component of withAuthenticator HOC is empty.
import { withAuthenticator } from "#aws-amplify/ui-react";
export const App = withAuthenticator((props) => {
console.log('props',props) // {}
return (
<BrowserRouter>
......
</BrowserRouter>
);
});
The thing I want to accomplish is sign-out functionality. I tried Auth.signOut() .But this is just clearing the localStorage but redirecting to sign-in page is not happening.
I searched for such issue and found out that
When using the Auth.signOut from within the withAuthenticator it will
not sign out because it is only updating the session locally in
LocalStorage. You need to have a way to rerender the actual
withAuthenticator component.
https://github.com/aws-amplify/amplify-js/issues/1529
https://github.com/aws-amplify/amplify-js/issues/4643
Solution that provide includes using props.onStateChange but the props in my case is empty.
Where am I wrong?

After some R&D I found that
import { withAuthenticator } from "#aws-amplify/ui-react";
Here withAuthenticator HOC doesn't provide any props.
And this approach is used to use pre-built UI components
import { withAuthenticator } from "aws-amplify-react";
Here withAuthenticator HOC provides props
authState
authData
onStateChange.
And this approach is used to customize (create) our own UI.

Related

React context API when wrapped around index.js file it's display nothing

I am learning about context API and creating an add basket functionality in the Context.js file I have created a context that which will I use for my application it's code is
import React, { createContext } from "react";
const Cart = createContext();
function Context({ childern }) {
return <Cart.Provider>{childern}</Cart.Provider>;
}
export default Context;
now I am wrapping my App component around it in the index.js file
import Context from "./context/Context";
<Context>
<App />
</Context>
but after doing this on the browser it display nothing no error not a single component that I have created is displayed but when I unwrapped the component it works fine
function Context({ props }) {
return <Cart.Provider>{props.childern}</Cart.Provider>;
}
Now it will work. Just add "props" in props and "props.children" in provider.

Keep state while navigating between component in react-router

Let's say I want to have a reusable react component in my project. I also want that component to have its state under different locations without losing it during component unmount. What is the correct way to deal with this kind of architecture in React? In other words, when the user navigates between these two routes react unmounts the previous component, therefore it loads remote data on every navigation between /user and /groups routes.
I also know that there is something called Redux. I don't see a clear way how to do it using reduct. Do I need two reducers? one for Users and the other for Groups? If so it's quite inconvenient creating a new reducer and write new logic each time when I need to use ReusableComponent.
Here is a similar skeleton to describe what I am trying to do. Any hint would be helpful.
//Router example
<Router>
<Switch>
<Route exact path=”/users” >
<UserComponent>
<ReusableComponent url=”http://apidomain.com/users” />
</UserComponent>
</Route>
<Route exact path=”/groups” >
<GroupComponent>
<ReusableComponent url=”http://apidomain.com/groups” />
</GroupComponent>
</Route>
</Switch>
</Router>
//ReusableComponent Example
<ReusableComponent>
--->use url, that passed from parent component tree(users or groups) to load data and keep in state
<ReusableComponentContext>
<Head />
<Body />
<Footer />
</ReusableComponentContext>
</ReusableComponent>
EDIT
So to describe my problem better is I need to have the same component with two or more parallel state on the different locations without overriding each other. If it's possible
I would use the "React Context" api. The context wrappes your app so if one component updates/ rerenderes the state which is stored inside of the context stayes untouched. To use Context you need three files:
"UserContext" = Example => rename!
Context Component (UserContext)
import { createContext } from "react"
export const UserContext = createContext(initValue)
Parent Component (Provider)
//filename: UserContext.js
//* import React, { useState } from "react"
//* import UserContext from "./UserContext"
const [state, setState] = useState("initState")
//* return(
<UserContext.Provider value={{state, setState}}> //value="props"
<ChildComponent/>
</UserContext.Provider>
Child Component (Consumer)
//*import React, { use Context } from "react";
//*import {UserContext} from "./UserContext"
const data = useContext(UserContext) //here "UserContext"
src: short explenation of usage
Edit: consuming with a custom hook
To avoid one import-statement you can create a custom Hook like this
import React, { use Context } from "react";
import {UserContext} from "./UserContext";
const useUserContext = (()=>{
const {state, setState} = useContext(UserContext)
//use effect if you want to set the context? with the hook...
return[state, setState]
})
in your remounting component
import useUserContext from "./useUserContext"
//rfce{
const {state, setState} = useUserContext()
//}
you can connect ReusableComponent to a piece of your redux store (see connect for more details).
import { connect } from "react-redux";
const ReusableComponent = (props) => {
// some logic before return
return <div>{props.magicProperty}</div>
}
const mapStateToProps = (state) => ({ magicProperty: state.magicProperty });
return connect(mapStateToProps)(ReusableComponent);
So every time you use ReusableComponent in you app, the magicProperty is shared, You can also connect some actions to the component in order to manage that part of state in the classical redux flow.
I think I found the solution. In my case, I had some misunderstanding on what level put context provider tag in the router component tree. So in React, it's very important to put the context provider wrapper in the right location. It holds a dedicated state only for those child components that are wrapped by that context provider.
In my case, I had ReusableComponentContext inside ReusableComponent and that was the wrong approach Because everywhere I used ReusableComponent it had individual context(Therefore individual state). I moved ReusableComponentContext on the top of a couple of components to solve my problem.

Redux connect "blocks" navigation with react-router-redux

In an application using react, redux and react-router, I'm using react-router-redux to issue navigation actions. I found that wrapping routes in a component with connect blocks navigation.
I made a sample with CodeSandbox that illustrates the issue: sample.
As is, the navigation doesn't work. However, if in ./components/Routes.jsx, this line:
export default connect(() => ({}), () => ({}))(Routes);
Is replaced by:
export default Routes;
It works.
Any idea how I could use connect in a component that wraps routes without breaking navigation?
See the troubleshooting section in react-redux docs.
If you change Routes.jsx export to:
export default connect(() => ({}), () => ({}), null, { pure: false })(Routes);
it will work.
This is because connect() implements shouldComponentUpdate by default,
assuming that your component will produce the same results given the
same props and state.
route changes, but props don't so the view doesn't update.
You could achieve same with withRouter hoc.
Not meant to be a duplicate.
I fixed it with withRouter like this
import { withRouter } from 'react-router-dom';
and
export default withRouter( connect(mapStateToProps)(App) );
See Redux, Router integration docs here
Have you ever encountered the warning message:
Warning: You cannot change <Router history>
Well use withRouter from react-router-dom
I have searched for this for so long because the Redux was recreating my App.jsx component which has <Route> </Route> as parents and this warning just freezes the routing in my app. I wanted to have React/Redux component, because I needed to pass authenticated props to the Route component, and redirect base on it, simple.
So import { withRouter } from 'react-router-dom'
and surround your component which is connected to redux with:
export default withRouter(connect(mapStateToProps)(App));
Something more:
Most of the times if you want to communicate with the router, takes some props, pass something else to it, get history, locations form it and you are using Redux in your app, surround this component with withRouter and you will have access to these properties as props.

Access browserHistory in redux

How can I access browserHistory on redux? I'm passing the browserHistory to a browserRouter from react-router. I want a reducer to listen for an action and the push another url. What's the best solution for this?
First, you'll need to have access to the Route props like history, location, and match in a component. You will have these props automatically if the rendered component was created by a Route component from react-router. Otherwise, you will need to use withRouter from react-router to decorate your component with the Route props.
Example using withRouter:
// MyComponent before
import { connect } from 'react-redux'
const MyComponent = (props) => (<div>{props.message}</div>)
export default connect()(MyComponent)
// MyComponent after
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
const MyComponent = (props) => (<div>{props.message}</div>)
export default withRouter(connect()(MyComponent))
In the after example, MyComponent you will have access to history under props.history (or this.props.history if in a class component).
After you have access to history in your component, you can redirect the app using props.history.push('/a/new/url'). It sounds like you want to use it in an action to change the state. If that's the case, I recommend passing in your reference to history into the action as an argument. Here is an example of an action which creates a new Post and then redirects to a list view of Posts in the same category. Note: I'm using redux-thunk in this example in order to be able to dispatch async actions.
In my PostForm component, I create a variable for history:
const rrHistory = this.props.history
Later, I pass this variable into the createPost action when the Save button is clicked:
createPost(model.title, model.body, model.author, model.category, rrHistory)
Then in the action code, after some async stuff finishes with the API server, we use the rrHistory variable reference to redirect to the categories list view:
rrHistory.push(`/${postCategory}/${newPost.id}`)
Note, that this is a working example, but it is far from perfect. You can also check out this SO Answer for other navigation ideas Programmatically navigate using react router V4
import { withRouter } from 'react-router-dom';
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Header));

Automatic redirect after login with react-router

I wanted to build a Facebook login into my react/react-router/flux application.
I have a listener registered on the login event and would like to redirect the user to '/dashboard' if they are logged in. How can I do that? location.push didn't work very well, except after reloading the page completely.
React Router v3
This is what I do
var Router = require('react-router');
Router.browserHistory.push('/somepath');
React Router v4
Now we can use the <Redirect>component in React Router v4.
Rendering a <Redirect> will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects.
import React, { Component } from 'react';
import { Redirect } from 'react-router';
export default class LoginComponent extends Component {
render(){
if(this.state.isLoggedIn === true){
return (<Redirect to="/your/redirect/page" />);
}else{
return (<div>Login Please</div>);
}
}
}
Documentation https://reacttraining.com/react-router/web/api/Redirect
React Router v0.13
The Router instance returned from Router.create can be passed around (or, if inside a React component, you can get it from the context object), and contains methods like transitionTo that you can use to transition to a new route.
React Router v2
Even though the question is already answered, I think it's relevant to post the solution that worked for me, since it wasn't covered in any of the solutions given here.
First, I'm using the router context on my LoginForm component
LoginForm.contextTypes = {
router: React.PropTypes.object
};
After that, I can access the router object inside my LoginForm component
handleLogin() {
this.context.router.push('/anotherroute');
}
PS: working on React-router version 2.6.0
React Router v3
Navigating Outside of Components
create your app with Router like this
// Your main file that renders a <Router>:
import { Router, browserHistory } from 'react-router'
import routes from './app/routes'
render(
<Router history={browserHistory} routes={routes} />,
mountNode
)
Somewhere like a Redux middleware or Flux action:
import { browserHistory } from 'react-router'
// Go to /some/path.
browserHistory.push('/some/path')
// Go back to previous location.
browserHistory.goBack()
react-router/tree/v3/docs
React Router v4.2.0
I am using React-16.2.0 & React-router-4.2.0
And I get solution by this code
this.props.history.push("/");
My working code:
.then(response => response.json())
.then(data => {
if(data.status == 200){
this.props.history.push("/");
console.log('Successfully Login');
}
})
I was following this document redirect-on-login-and-logout
I was also try by return <Redirect to='/' /> But unlucky, this not working for me.
React router v5 using hooks
These steps are for authorisation redirect. But can be used for login/logout redirection also.
The <Redirect/> accepts to prop as a string or an object. We can utilise the object to pass the redirection path after login/logout using hooks easily.
Get the pathname of url from where the <Redirect/> is called using
useLocation()
const {pathname} = useLocation()
In the to prop of <Redirect/> pass in the following object:
<Redirect to={{pathname:'/login',state: {referrer: pathname}}/>
In the Login component access the route state variable using useLocation() hook and use the useHistory() hook to redirect after successful login.
const history = useHistory();
const location = useLocation();
const login() => {
// After login success
const {state: {referrer}} = location;
history.push(referrer)
};
Check the official docs here
React Router v3
Navigating inside components
You should use withRouter decorator when it's necessary to redirect inside a component. The decorator uses context instead of you.
import {withRouter} from 'react-router'
fucntion Foo(props) {
props.router.push('/users/16');
}
export default withRouter(Foo);
withRouter(Component, [options])
A HoC (higher-order component) that wraps another component to enhance
its props with router props.
withRouterProps = {
...componentProps,
router,
params,
location,
routes
}
Pass in your component and it will return the
wrapped component.
You can explicit specify router as a prop to the wrapper component to
override the router object from context.
In your store:
data.router.transitionTo('user');
And router has:
"Route name="user" handler={User}"
User is route handler

Resources