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

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

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;

How to display a component in react js according to api response.?

Iam trying to display a component whenever response of an api is true. but if i try to do it in the axios where iam sending api request it does not work and if i remove the below return it gives me an error that there is nothing to render.
My code
import React from "react";
import { useState, useEffect } from "react";
import { SignUpComponent } from "../index";
import axios from "axios";
import { Redirect, useParams } from "react-router-dom";
import { getToken } from "../../common/constants/variables";
function Reference() {
const [openSignUp, setOpenSignup] = useState(true);
const [refer, setRef] = useState({});
let { ref } = useParams();
function toggleToSignUp() {
setTimeout(() => {
setOpenSignup(true);
}, 350);
}
axios
.post("https://theappsouk.com/api/v1/check-referral", {
ref: ref,
})
.then((response) => {
if (response.data.status == true) {
return (
<SignUpComponent open={openSignUp} toggleModal={toggleToSignUp} />
);
} else{
<Redirect to= '/'/>
console.log("NOTHING")
}
console.log("REFFEERR", JSON.stringify(response.data.status));
});
console.log("REFF", JSON.stringify(ref));
return ( //what ever the api response is it seems to render only this return statement
<div>
<SignUpComponent open={openSignUp} toggleModal={toggleToSignUp} />
</div>
);
}
export default Reference;
you should request axios in the useEffect, and display all the UI inside the return
import React from "react";
import { useState, useEffect } from "react";
import { SignUpComponent } from "../index";
import axios from "axios";
import { Redirect, useParams } from "react-router-dom";
import { getToken } from "../../common/constants/variables";
function Reference() {
const [openSignUp, setOpenSignup] = useState(true);
const [status, setStatus] = useState(true);
const [refer, setRef] = useState({});
let { ref } = useParams();
function toggleToSignUp() {
setTimeout(() => {
setOpenSignup(true);
}, 350);
}
useEffect(() => {
axios
.post("https://theappsouk.com/api/v1/check-referral", {
ref: ref,
})
.then((response) => {
setStatus(response.data.status)
});
}, []);
return ( //what ever the api response is it seems to render only this return statement
<div>
{
status? <SignUpComponent open={openSignUp} toggleModal={toggleToSignUp} /> :
<Redirect to= '/'/>
}
</div>
);
}
export default Reference;

Why setState does not change value?

Why is below code not working?
It returns false even when I set inverted to true;
it also logs hit so it does reach.
import React, { useEffect, useState } from 'react';
import { ComponentProps } from 'react';
import { useHistory } from 'react-router-dom';
type Props = {
} & ComponentProps<'div'>;
export function HeaderMaster({
...props
}: Props) {
const [inverted, setInverted] = useState(false);
const history = useHistory()
useEffect(() => {
setInverted(true); // this does work
history.listen((location) => {
console.log(location.pathname);
if (location.pathname === '/bestellen') {
setInverted(true); // this does not
console.log('hit');
}
else {
setInverted(false);
}
})
},[history]);
useEffect(() => {
console.log(inverted);
},[inverted])
return (
<>
</>
);
}

How change url with react-router

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;

React custom hook using only useEffect

I created a custom hook that uses useEffect to update a redux store when certain values in the store change:
import { useRef, useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { index } from '../actions'
import { createSelector } from 'reselect'
import { omit } from 'lodash'
const selectPerformanceSearch = createSelector(
state => omit(state.eventSearch, ['results', 'isFetching']),
items => items
)
export default function useEventSearch() {
const state = useSelector(selectEventSearch)
const dispatch = useDispatch()
const initialFetch = useRef(true)
const { tags, near, filters } = state
const { lng, lat, location } = near
useEffect(() => {
if (!initialFetch.current) {
const data = { tags, lng, lat, filters }
dispatch(index('/event/search', 'EVENT_SEARCH', data))
}
}, [tags, lng, lat, filters, dispatch])
useEffect(() => {
if (initialFetch.current && location) {
initialFetch.current = false
const data = { lng, lat }
dispatch(index('/event/closest', 'EVENT_SEARCH', data))
}
}, [lng, lat, location, dispatch])
}
Then I have a React component that uses the hook like so:
import useEventSearch from '../../hooks/usePerformanceSearch'
const SearchBar = props => {
// ...code
usePerformanceSearch()
/// ...other code
return ( ... )
}
It all works as I would expect but is it ok to just call and use a hook the way I did?

Resources