How change url with react-router - reactjs

I have some component
import { RouteComponentProps, withRouter } from 'react-router';
function MySearchComponent({ match, location, history }: RouteComponentProps) {
const [query, setQuery] = useState<string>('');
useEffect(() => {
console.log('all fine!')
history.replace(`/my_search_page?query=${query}`);
}, [query]);
// some code for change query
}
export const MySearch = withRouter(MySearchComponent);
What's wrong? I'd tried to use history.push
console.log alter right when query changed, but nothing happend
UPD: Sorry. It was my mistake: my application just doesn't support search-parameters
Thanks for your help

In my application I am using useHistory hook
import React, { useEffect } from "react";
import { useHistory } from "react-router-dom";
const Operations = () => {
const history = useHistory();
useEffect(() => {
const res = prepareURLParams(filters);
history.push(getRouterString("/", res));
}, [filters]);
}
export default Operations;

Related

export 'withRouter' (imported as 'withRouter') was not found in 'react-router-dom'

I am totally a beginner in React and while practising I ran into this issue. Through searching, I found out that 'withRouter' is not supported anymore by 'react-router-dom v6'. But I can't figure out how to change my code compatibly to v6. Does anyone know how to change this code instead of using 'withRouter'? Thanks in advance!
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { readPost, unloadPost } from '../../modules/post';
import PostViewer from '../../components/post/PostViewer';
const PostViewerContainer = ({ match }) => {
// 처음 마운트될 때 포스트 읽기 API요청
const { postId } = match.params;
const dispatch = useDispatch();
const { post, error, loading } = useSelector(({ post, loading }) => ({
post: post.post,
error: post.error,
loading: loading['post/READ_POST']
}));
useEffect(() => {
dispatch(readPost(postId));
// 언마운트될 때 리덕스에서 포스트 데이터 없애기
return () => {
dispatch(unloadPost());
};
}, [dispatch, postId]);
return <PostViewer post={post} loading={loading} error={error} />;
};
export default withRouter(PostViewerContainer);
enter image description here
That is correct, the withRouter Higher Order Component (HOC) was removed in react-router-dom#6.
Since PostViewerContainer is a function component, just use the React hooks directly. There's no need really for the withRouter HOC. In this case it's the useParams hook you need to import and use.
Example:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom'; // <-- import useParams hook
import { readPost, unloadPost } from '../../modules/post';
import PostViewer from '../../components/post/PostViewer';
const PostViewerContainer = () => { // <-- remove match prop
// 처음 마운트될 때 포스트 읽기 API요청
const { postId } = useParams(); // <-- call hook and destructure param
const dispatch = useDispatch();
const { post, error, loading } = useSelector(({ post, loading }) => ({
post: post.post,
error: post.error,
loading: loading['post/READ_POST']
}));
useEffect(() => {
dispatch(readPost(postId));
// 언마운트될 때 리덕스에서 포스트 데이터 없애기
return () => {
dispatch(unloadPost());
};
}, [dispatch, postId]);
return <PostViewer post={post} loading={loading} error={error} />;
};
For reference, if you needed to still use an HOC for class based components you'd need to either convert them to function components or create a custom withRouter HOC.
Example:
import { useLocation, useNavigate, useParams } from 'react-router-dom';
const withRouter = Component => props => {
const location = useLocation();
const navigate = useNavigate();
const params = useParams();
return (
<Component
{...props}
location={location}
navigate={navigate}
params={params}
/>
);
};
export default withRouter;

Redirect react-router-dom v6

I have a problem, watching a video on youtube that used history.push('/login?redirect=shipping'), how can I modify it using navigate, because if I use the string navigate ('/ login?redirect=shipping') even if logged in it returns to home page and does not go to the shipping page.
I solved the problem in this way :
const checkoutHandler = () => {
if(!userInfo){
navigate('/login')
} else{
navigate('/shipping')
}
}
Your solution is good.
Can I fill in some gaps?
We need to get the state of user to check if user logged in to proceed with if statement.
After this your solution will work.
import React from 'react'
import { useNavigate } from 'react-router-dom'
import { useSelector } from 'react-redux'
//....some imports
const CartScreen = () => {
//.......some code before
const navigate = useNavigate()
const userLogin = useSelector((state) => state.userLogin)
const { userInfo } = userLogin
const checkoutHandler = () => {
if (!userInfo) {
navigate('/login')
} else {
navigate('/shipping')
}
}
//...return JSX...
**Try this one.
const navigate = useNavigate()
const checkoutHandler = () => {
navigate('/signin?redirect=/shipping')
}
Have you sort out this problem or not? If you are facing the same problem then I suggest you go on your login page and make some changing.
Import useHistory and useLocation:
import { Link, useHistory, useLocation } from 'react-router-dom'
Then in functions apply this:
const history = useHistory();
const location = useLocation();

TypeError: Cannot read properties of undefined (reading 'search')

I am completely new to this. Tried for hours to find some sort of explanation on this.
Basically I am trying to replicate a project to understand the main concepts. In the project the code apparently works just fine, I however receive a "TypeError: Cannot read properties of undefined (reading 'search')" error. I hope that someone here can explain to me, what I am missing.
I believe the Errors to come from the following lines of code:
SigninScreen:
const redirect = props.location.search
? props.location.search.split("=")[1]
: "/";
ProductScreen:
const productId = props.match.params.id;
Kind Regards,
Makani
SigninScreen:
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, } from "react-router-dom";
import { signin } from "../actions/userActions";
import Loadingbox from "../components/LoadingBox";
import MessageBox from "../components/MessageBox";
export default function SigninScreen(props) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const redirect = props.location.search
? props.location.search.split("=")[1]
: "/";
const userSignin = useSelector((state) => state.userSignin);
const { userInfo, loading, error } = userSignin;
const dispatch = useDispatch();
const submitHandler = (e) => {
e.preventDefault();
dispatch(signin(email, password));
};
useEffect(() => {
if (userInfo) {
props.history.push(redirect);
}
}, [props.history, redirect, userInfo]);
return ( ... );
}
ProductScreen:
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, useParams } from "react-router-dom";
import { detailsProduct } from "../actions/productActions";
import LoadingBox from "../components/LoadingBox";
import MessageBox from "../components/MessageBox";
import Rating from "../components/Rating";
export default function ProductScreen(props) {
const productId = props.match.params.id;
const dispatch = useDispatch();
const [qty, setQty] = useState(1);
const productDetails = useSelector((state) => state.productDetails);
const { loading, error, product } = productDetails;
useEffect(() => {
dispatch(detailsProduct(productId));
}, [dispatch, productId]);
const addToCartHandler = () => {
props.history.push(`/cart/${productId}?qty=${qty}`);
};
return ( ... );
}
I had same error.
In v6 you have to use useLocaion() like:
const location = useLocation();
const redirect = location.search
? location.search.split('=')[1]
: '/';
From the documentation for React Router v5:
The router will provide you with a location object in a few places:
· Route component as this.props.location
· Route render as ({ location }) => ()
· Route children as ({ location }) => ()
· withRouter as this.props.location
A component receives the location prop automatically in 4 usages mentioned about. Since you have not described withRouter, I can only assume that your case is Option 1.
React Router adds the location prop to the component automatically if it is directly in the Route component.
// if this is the case, SignIn receives a location prop
<Route path="/path" component={SigninScreen} />
If you want to add location prop manually, you can use withRouter higher order component.
export default withRouter(SignInScreen);

How do I combine useLocation() with useSelector()?

import React from "react"
import { useSelector } from 'react-redux'
import { useLocation } from "react-router"
const BreadCrumb = () => {
const location = useLocation()
const currentPageTitle = useSelector(state => {
// match current location to get the currrent page title from redux store and return it
})
return (
<h2>Home / { currentPageTitle}</h2>
)
}
export default BreadCrumb
This code works fine in the initial render and I do get the intended result { currentPageTitle } but the UI doesn't seem to re-render and stays the same despite route change. Although, if I console.log( location ) before the return statement, it logs successfully on route change. What is the issue here?
I would suggest that you use useEffect hook:
import React, { useEffect, useState } from "react"
import { useSelector } from 'react-redux'
import { useLocation } from "react-router"
const BreadCrumb = () => {
const location = useLocation()
const [currentLocation, setCurrentLocation] = useState('')
const currentPageTitle = useSelector(state => {
console.log(currentLocation);
// Do something with currentLocation
})
useEffect(() => {
if (location) {
setCurrentLocation(location.pathname)
} else {
setCurrentLocation('')
}
}, [location])
return (
<h2>Home / { currentPageTitle}</h2>
)
}
export default BreadCrumb

I can't get the props.match.params.id. It's said props is undefined

I've tried to get the id from the URL (with props.match.params.id) and pass it into a variable to reuse it. But props is undefined. I don't know why.
Anyone can see if I've done something wrong?
import React, { useState, useEffect } from "react";
import axios from "axios";
export default function Recipes() {
const [recipes, setRecipes] = useState([]);
useEffect(() => {
const id = props.match.params.id;
const getRecipes = async () => {
const url = `http://localhost:8000/user/recipes/${id}`;
const result = await axios.get(url);
setRecipes(result.data);
console.log("test", recipes);
};
getRecipes();
}, []);
return (
<div>
{recipes.map(recipe => (
<p>{recipe.title}</p>
))}
</div>
);
}
You need to make use of the useParams hook from react-router-dom for this instead.
Try this:
...
import { useParams } from 'react-router-dom'
export default function Recipes() {
...
const { id } = useParams()
useEffect(() => {
...
}, [id])
...
}
I think you forgot to add props in your functional component :
You can solve the error "It's said props is undefined"
By Change this :
export default function Recipes() {
TO
export default function Recipes(props) {
Ah! I think you forget it add props as a param to you component. This is something I do very often.
Your component should be like this
export default function Recipes(props) {
//Your content
}

Resources