DataSearch and RR Redirect - reactjs

I'm using ReactiveSearch search components to build a nice UI for my search app. I'm using the prop onQueryChange to invoke a function that uses to route to the search results page after user has submitted a search query.
How can I use React Router v4's to redirect to search results page after user has submitted query with the DataSearch component?
So far I have
<DataSearch
..
onQueryChange={
(prevQuery, nextQuery) => {
console.log("prev query: ", prevQuery);
console.log("next query: ", nextQuery);
{ nextQuery !== '' &&
<Redirect to="/results"/>,
}
}
}
I looked here and tried to change it for my use case. However, its not working.
UDPATE:
In regards to my comment below. I remembered that I had asked a similar question before, so I went to my profile to see if I could find it and I did. I combined that info with this and I believe I was able to come up with the solution:
if (redirect) {
return <Redirect to={{
pathname: '/search',
state: { pathname: this.state.redirect }
}}/>
}

For redirection it would be better to use onValueSelected (docs) since query would change everytime you type something in the searchbox (in order to fetch the suggestions).
In order to handle redirection declaratively with React router 4, you would update the state of your parent component when a value is selected and conditionally render the Redirect component from react router. For example,
Demo
class Main extends Component {
state = {
redirect: false
};
render() {
const { redirect } = this.state;
if (redirect) {
// when this renders it would redirect to the specified route
return <Redirect to="/search" />;
}
return (
<ReactiveBase
...
>
<DataSearch
...
onValueSelected={(value, cause, source) => {
// just setting the redirect state to true for redirection
this.setState({
redirect: true
});
}}
/>
</ReactiveBase>
);
}
}
An alternate way would be to use withRouter higher order component from React Router but the above method would also work.

Related

React JS need to get data from one page to other

I am trying to make a test project where I have a product list page and a checkout page now when I click on the products add to cart button it should save the data into a useState array and I should be able to pass the data from the state to the checkout page. I am kinda stuck please help
You can use the Link component from React-Router:
<Link
to={{
pathname: `/checkout/${productId}`,
state: { data:productData }
}}
/>
or you can use history.push() for example:
props.history.push({
pathname: `/checkout/${productId}`,
state: { data:productData }
});
According to this, you can consume the state like that:
const Checkout = (props) => {
const {state} = props.location
return <></>
}

Pass props to another component using react redirect

I have the following code
if (_get(this.state, 'showCheckoutSuccess') == false) {
alert("Order Failed: Not Enough Credits");
return <Redirect push to={{
pathname: '/view-cart',
}} />;
}
what it does orginally is just show a popup after redirect. But I want to be able to pass the showCheckOutSuccess info to that component to display a message on a line of the page.
I am not having any luck what I have tried doing was this:
if (_get(this.state, 'showCheckoutSuccess') == false) {
return <Redirect push to={{
state: { showCheckoutSuccess: "false" }
pathname: '/view-cart',
}} />;
}
and then using this.props.location.state.showCheckoutSuccess
this results in an error when i normally navigate to the cart page and it says that showCheckoutSuccess is undefined.
I think its because the info was never passed to it but users should still be able to get to the cart page even if this error never comes up.
You need redux or some other state manager (React Context will work too).
Or you can use the history hook.
history.push({
pathname:"/view-cart",
state:{
showCheckoutSuccess: "false"
}
});
and then access it like props.location.state.showCheckoutSuccess.

componentDidMount always called before react render

I am new to react world, I tried to fetch user data from axios call, and tried to get the data before the react's render executed.
How I call this component
<Route path="/users" render={(props) => <User {...props}/>} />
Here is my component class
class User extends React.Component {
constructor(props) {
super(props);
this.state = { authenticated: false }
this.getCurrentUser = this.getCurrentUser.bind(this);
}
componentDidMount(){
console.log("componentDidMount");
this.getCurrentUser();
}
getCurrentUser(){
Api.getCurrentUser().then(response => {
if (response) {
console.log(response.data.username);
this.setState({authenticated: true});
}
}).catch(error =>{
this.setState({authenticated: false});
}
}
render() {
console.log(this.state.authenticated);
if (this.state.authenticated === false) {
return <Redirect to={{ pathname: '/login' }}/>
}
return (
<div><Page /> <div>
);
}
}
export default User;
The console.log sequence is
false
componentDidMount
user_one
Warning: Can't perform a React state update on an unmounted component. This is a no-op
The warning makes sense because react already redirect me to login so the user component is not mounted.
I don't understand why componentDidMount is not called before render, because it supposes to change the defaultState through this.setState()...
What am I missing here?
ComponentDidMount works the way you described it. It runs immediately after the component is rendered. What you can do is to wrap your Component with a parent component where you have the API call and pass on the isAuthenticated as props to .
Docs for reference
As #user2079976 rightly stated, your usage of componentDidMount is correct & it behaves the way it is intended to, but I think you might be getting the wrong impression due to your code execution workflow.
Problem Reason
This issue/warning is generally something to go with when you're updating a component that has unmounted, in your case it's likely the redirect that happens before your api return a result.
More Details:
Not having the full code sample, I had to guess a few of the variables in your setup & I'm unable to get the exact issue on my JsFiddle as you've explained (I think JsFiddle/react.prod swallows the warning messages), but... I'll try to update this fiddle to explain it as much as I can with comments.
// at render this is still false as `state.authenticated`
// only becomes true after the redirect.
// the code then redirects....
// then updates the not yet mounted component & its state
// which is causing the warning
if (this.state.authenticated === false) {
return (<Redirect to={{ pathname: '/about' }}/>)
}
return (<div>On Home</div>);
Possible Solution
Rather do your auth/logged-in (state) to a higher level/parent component, and have the router decide where to send the user.
We have used this exact example in one of our apps (which is an implementation of the above suggestion). It works well for an auth type workflow & is straight from the docs of the Router lib you're using :P https://reactrouter.com/web/example/auth-workflow

ReactJS + Router how to access a Redirect's state functional components

On the official documentation, it says that to access the state that is passed into the component redirected to, you can use
this.props.location.state
However I'm not using class components and therefore I don't have this..
How do I access the passed state in my redirected component?
<Redirect
to={{
pathname: "/signin",
state: { from: props.location, alert: true },
}}
/>
The following function identifies is there is an alert passed in the state on Redirect. In case alert:true it displays the <div>
let location = useLocation()
function DashboardRedirectAlert() {
if (location.state?.alert) {
return <div className="alert alert-warning">Please Signin first</div>;
} else {
return <></>;
}
}
When you try to refer to functional components like the one above, make sure there is something to return always.
In the functional component , there is no this,so you can directly any state by props.''attribution''
You don't allow using this in functional component. The true code is:
Props.location.state.
In fact this keyboard removed because in class components when we want to reach functions and attributes and state use this but you use functional component,so not need use this.
It works in functional components well. To access the value in the redirected url
use
{( typeof props.location.state != "undefined" ) && props.location.state }
You also need to add a check for undefined in case you visit the page without the redirection
In a functional component the state prop is available on the location object returned from the useLocation() hook.
This example uses optional chaining to test if state exists and contains myVariable.
function LinkToComponent(props) {
return (
<Link
to={{
pathname: `/myRoute/${props.id}`,
state: { myVariable: true },
}}
>
Click me
</Link>
);
}
function LinkedToComponent(props) {
const location = useLocation();
// will render only if `myVariable` was passed as `true` in Link state
{
location.state?.myVariable && <p>my variable is true</p>;
}
}

Route handling a uniquely generated URL specific to a user in ReactJS and react-router-dom v4

In the app I am working on if a user forgot their password, they click on a link that brings them to a page where they enter the username. If the username is matched, it sends a uniquely generated URL to the email associated with the username. For example:
http://localhost:8000/auth/security_questions/0e51706361e7a74a550e995b415409fdab4c66f0d201c25cb4fa578959d11ffa
All of this works fine, but I am trying to figure out how to handle this on the front-end routing using React and react-router-dom v4. I made this route.
<Route exact path='/auth/security_questions/:key' component={SecurityQuestions} />
The correct component loads related to security questions, but that is not the behavior I am after. After all, it takes anything you put after security_questions/.
What it should be doing is matching :key against the database before it loads the component.
I'm not sure about a few things:
1) How to parse out the :key portion so that I can pass it as a value to verify against the database.
2) While I have a general idea of how to handle the verification, I am not sure how to tell React: "Ok, the key has been verified in the database. Finish loading the component."
I think it would in general look like:
// ./containers/security_questions.js
componentWillMount() {
this.props.verifyKey(:key);
}
And then actions:
// ./actions/authentication.index.js
export function verifyKey({ :key }) {
return function(dispatch) {
axios
.post(
`${ROOT_URL}/api/auth/security_questions/`,
{ :key }
)
.then(response => {
dispatch('Finish loading the rest of the component')
})
.catch(error => {
dispatch(authError(error.response.data.non_field_errors[0]));
});
}
}
Or maybe instead of it finishing loading the component, it should just route to a different URL that is a protected route.
You can grab the params from the path like so (https://reacttraining.com/react-router/web/api/Route):
<Route path="/user/:username" component={User}/>
const User = ({ match }) => <h1>Hello {match.params.username}!</h1>
You will want to conditionally render based upon some state set by verifyKey.
componentWillMount() {
this.props.verifyKey(this.props.match.params.key);
}
render() {
if (this.state.permitRender) {
return <Component>
} else {
return <LoadingComponent />
}
You can use the render method on the route to put in your verification logic and render the appropriate control. You would need to move the action to verify the key to the component which renders the route, rather than the SecurityQuestions component.
<Route exact
path='/auth/security_questions/:key'
render={(props)=>{
let finalComponent= <ComponentToRenderWhenKeyDoesNotMatch/>;
if(this.props.verifyKey(props.match.params.key)){
resultantComponent=<SecurityQuestions/>
}
return finalComponent;
}}
/>
Route params will be inside the match.params prop:
componentWillMount() {
this.props.verifyKey(this.props.match.params.key);
}
See https://reacttraining.com/react-router/web/example/url-params
--
Then on the success of your security questions I would set some state in your reducer and render based on that.

Resources