I'm a newbie in React and I'm trying to make a basic meal app. In App component, I'm searching for meal and fetching data from my api and clicking on any meal for its detail page. However, on detail page when searching a new meal it doesn't work. How can I solve this problem?
Thanks for your answer in advance.
It's my App.js
import React,{ useState } from 'react';
import { BrowserRouter, Route, } from 'react-router-dom';
import Header from './components/Header'
import Search from './components/Search'
import MealList from './components/MealList'
import MealDetail from './components/MealDetail'
import axios from 'axios';
import styles from './App.module.css';
function App(props) {
const [meals, setMeals] = useState([]);
const [isLoaded, setIsLoaded] = useState(true);
console.log(props)
const getQuery = (query) => {
//history.replace('/');
setIsLoaded(false);
axios.get(`https://www.themealdb.com/api/json/v1/1/search.php?s=${query}`)
.then(response => {
setIsLoaded(true);
setMeals(response.data.meals)
})
}
return (
<BrowserRouter>
<div className={styles.body}>
<Header />
<div className={styles.container}>
<Search getQuery={getQuery} />
<Route path='/' exact render={() => <MealList meals={meals} />} />
<Route path='/meals/:id' component={MealDetail} />
</div>
</div>
</BrowserRouter>
);
}
export default App;
I solved this problem with "withRouter" in App component. It gave me some information with props and I redirected to the homepage when form submitting.
Related
I have 2 components both are exactly the same. one is redirected to when I click on a Navlink inside of my navbar that I created using react-bootstrap. The other component that is exactly the same just redirects to localhost:3000 and not "./member" when I click on the html button that should redirect to that component. Please help me.
the html button and the function to redirect look like
import {Link, Route, withRouter, useHistory} from 'react-router-dom'
const Posts = (props) => {
const dispatch = useDispatch();
const history = useHistory();
const getProfile = async (member) => {
// const addr = dispatch({ type: 'ADD_MEMBER', response: member })
console.log(member)
history.push('/member')
}
return (
<div>
<button onClick={() => getProfile(p.publisher)}>Profile</button>
</div>
)
}
export default withRouter(Posts);
The routes.js looks like
const Routes = (props) => {
return (
<Switch>
<Route path="/member" exact component={Member} />
</Switch>
)
}
export default Routes
The component that I am trying to redirect to is exactly the same as one that is redirected to and working when I click on it from the navlink. I have downgraded to history 4.10.1
My index.js is
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Router, Route } from 'react-router-dom';
import * as history from 'history';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import rootReducer from './reducers'
const store = createStore(rootReducer)
const userHistory = history.createBrowserHistory();
ReactDOM.render(
<Provider store = {store}>
<Router history={userHistory}>
<BrowserRouter>
<Route component={App} />
</BrowserRouter>
</Router>
</Provider>,
document.getElementById('root'));
serviceWorker.unregister();
When I wrap the app route in the url goes to ./member but it does not load.
<Switch>
<Route path="/" exact component={app} />
<Route path="/member" component={Member} />
</Switch>
<button onClick={() => history.push(`/${p.publisher}`)}>Profile</button>
When onClick event is triggered, I want to redirect to a new component (props passed to it) with a new url.
My App.js
import React from "react";
import Main from "./Components/Main/Main";
import "bootstrap/dist/css/bootstrap.min.css";
import styles from "./App.module.css";
import { BrowserRouter as Router, Route} from "react-router-dom";
import SearchBar from "./Components/SearchBar/SearchBar";
import AnimeInfo from "./Components/AnimeInfo/AnimeInfo";
import Cards from "./Components/Cards/Cards"
const App = () => {
return (
<Router>
<div className={styles.container}>
<SearchBar />
<Route path="/" exact component={Main} />
<Route path="/anime/info" component={AnimeInfo} />
<Route path="/anime/cards" component={Cards} />
</div>
</Router>
);
};
export default App;
In the following component, I am passing props to a component but I want to redirect to the url too, but doing so, the props passed that component are lost and I just get redirected
import React, { useEffect, useState } from "react";
import { apiDataTop, apiDataUpcoming, apiDataDay } from "../../api";
import styles from "./TopAnime.module.css";
import AnimeInfo from "../AnimeInfo/AnimeInfo";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
} from "react-router-dom";
const TopAnime = () => {
const [animeData, setAnimeData] = useState([]);
const [animeDataHype, setAnimeDataHype] = useState([]);
const [animeDataDay, setAnimeDataDay] = useState([]);
const [image_url, setImageUrl] = useState("");
useEffect(() => {
callApi();
}, []);
const callApi = async () => {
const results = await apiDataTop();
const hypeResults = await apiDataUpcoming();
const dayResults = await apiDataDay();
setAnimeData(results);
setAnimeDataHype(hypeResults);
setAnimeDataDay(dayResults);
};
console.log(animeDataDay);
return (
<div>
<h1>Recent Release</h1>
<div className={styles.container}>
<br />
{animeDataDay === []
? null
: animeDataDay.map((anime) => {
return (
<a
href
onClick={(event) => {
event.preventDefault();
let animeName = anime.title;
animeName = animeName.replace(/\s+/g, "");
setImageUrl(anime.image_url);
console.log("image url original", anime.image_url);
console.log("image url", image_url);
}}
className={styles.move}
>
<img src={anime.image_url} alt="anime" />
<div className={styles.size}>
<h5>
<b>{anime.title}</b>
</h5>
</div>
</a>
);
})}
{image_url ? (
<Router>
// below commented approch first display the component on the same page and then redirects to the url
// but the props passed are lost !
// <Link to="/anime/info">
// <AnimeInfo image_url={image_url} />
// {window.location.href = `/anime/info`}
// </Link>
<Route
path="/anime/info"
render={() => <AnimeInfo image_url={image_url} />}
/>
</Router>
) : null}
</div>
export default TopAnime;
Following is the component, to whom I want to pass props and use the data passed to display (on a whole new page)!
import React, { useEffect, useState } from "react";
import styles from "./AnimeInfo.module.css";
console.log("The data image props issss", props.image_url);
return (
<div className={styles.container}>
<h1> I am info component</h1>
<img src={props.image_url} alt="anime" />
</div>
);
};
export default AnimeInfo;
Why not use the state property in history.push()?
See it in action here
use the history package.
then create a file at 'src/history.js'
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
then in your component
import history from './history'
history.push({
pathname: '/path',
data_name: dataObject,
});
Then you can access the props in your other component:
this.props.location.data_name
Use render method in router
const renderComponent = (props, Component) => {
// write logic if needed
return <Component {...props} />
}
<Route path="/earner" render={(props) => renderComponent(props, Main)}/>
I want to have a simple button that when clicked redirects a user to a route defined in my Index.tsx file.
When the button is clicked, the url bar is correctly changed to "/dashboard", however my component (just an h1) does not appear. If I reload chrome at that point it will appear.
Here's my code (Index.tsx):
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Route, Switch } from "react-router-dom";
import { Router } from "react-router";
import { createBrowserHistory } from "history";
import Dashboard from "./components/Dashboard";
const appHistory = createBrowserHistory();
ReactDOM.render(
<React.StrictMode>
<Router history={appHistory}>
<Switch>
<Route exact path="/" component={App} />
<Route path="/dashboard" component={Dashboard} />
</Switch>
</Router>
</React.StrictMode>,
document.getElementById("root")
);
Here's my start of a Login form (the first route above, App, renders it).
(Login.tsx):
import React, { useState } from "react";
import {Button} from "#material-ui/core";
import { useHistory} from "react-router-dom";
export const Login: React.FC = (props) => {
const classes = useStyles();
let history = useHistory();
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const validateForm = (): boolean => {
return true;
};
const handleLoginClick = (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
history.push("/dashboard");
};
return (
<form>
<div>
<Button
onClick={handleLoginClick}
color="inherit"
type="button"
>
Login
</Button>
</div>
</form>
);
};
export default Login;
Replace this line
import { Router } from "react-router"
with
import {BrowserRouter as Router } from "react-router-dom";
Try importing the Router from react-router-dom - the rest seems correct
import { Route, Router, Switch } from "react-router-dom";
react-router is mostly for internal usage - you only interact with react-router-dom
I am using Router and customHistory to help me redirect the pages, but the pages not render correctly.
The code works like this: if the user is authorized or log in, then the user should be redirected to "localhost:8080/dashboard" and see the dashboard(with data fetching from firebase) & header; if the use is log out, then the user should be redirect to "locahost:8080/" and see the log in button with the header.
However, after I successfully log in, the url is "localhost:8080/dashboard" without any data fetched from firebase, only things I can see are the header and login button. But if I hit "RETURN" with the current url which is "localhost:8080/dashboard", it will redirect to correct page with all data fetching from firebase, and no login button.
This is the github_link to the code.
I have spent times searching online, but do not find any positive result except this one. After reading the stackoverflow I feel my code has some problems with asynchronization. Any thoughts?
I really appreciate for your help! Thanks!
This is my AppRouter.js:
export const customHistory = createBrowserHistory();
const AppRouter = () => (
<Router history={customHistory}>
<div>
<Header />
<Switch>
<Route path="/" exact component={LoginPage} />
<Route path="/dashboard" component={ExpenseDashboardPage} />
<Route path="/create" component={AddExpensePage} />
<Route path="/edit/:id" component={EditExpensePage} />
<Route path="/help" component={HelpPage} />
<Route component={LoginPage} />
</Switch>
</div>
</Router>
);
This is my app.js
import React, { Children } from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import "normalize.css/normalize.css"; //Normalize.css makes browsers render all elements more consistently and in line with modern standards.
import "./styles/styles.scss";
import AppRouter, { customHistory } from "./routers/AppRouter";
import configureStore from "./redux/store/configStore";
import { startSetExpenses } from "./redux/actions/expenses";
import { login, logout } from "./redux/actions/auth";
import "react-dates/lib/css/_datepicker.css";
import { firebase } from "./firebase/firebase";
//for testing: npm test -- --watch
const store = configureStore();
const jsx = (
<Provider store={store}>
<AppRouter />
</Provider>
);
ReactDOM.render(<p>Loading...</p>, document.getElementById("app"));
let hasRendered = false;
const renderApp = () => {
if (!hasRendered) {
ReactDOM.render(jsx, document.getElementById("app"));
hasRendered = true;
}
};
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log("log in");
store.dispatch(login(user.uid));
store.dispatch(startSetExpenses()).then(() => {
renderApp();
if (customHistory.location.pathname === "/") {
customHistory.push("/dashboard");
}
});
} else {
console.log("log out");
store.dispatch(logout());
renderApp();
customHistory.push("/");
}
});
This is the header.js
import React from "react";
import { BrowserRouter, Route, Switch, Link, NavLink } from "react-router-dom";
import { connect } from "react-redux";
import { startLogout } from "../redux/actions/auth";
export const Header = ({ startLogout }) => (
<header>
<h1>Expensify</h1>
<NavLink to="/" activeClassName="is-active">
Dashboard
</NavLink>
<NavLink to="/create" activeClassName="is-active">
CreateExpense
</NavLink>
<button onClick={startLogout}>Logout</button>
</header>
);
const mapDispatchToProps = (dispatch) => ({
startLogout: () => dispatch(startLogout()),
});
export default connect(undefined, mapDispatchToProps)(Header);
'When i visit "/shop/hats" it shows only blank page. No error i could see. But when i put category component in 1st route, it works.'
'shop component'
import React from "react";
import CollectionPreview from "../../component/CollectionPreview/collectionPreview-com"
import {Route} from "react-router-dom"
import Category from "../../component/Category/category-com"
const Shop = ({match}) => {
console.log("Printing" + match.path);
return(
<div>
<Route exact path="/shop" component={CollectionPreview} />
<Route path="/shop/:categoryId" component={Category} />
</div>
)
}
export default Shop;
'Category component which is not rendering. but when i use this component in 1st route, it works '
import React from "react";
import "./category-style.css";
const Category = ({match}) => {
console.log(match);
return(
<div className="Test">
<h1>Test</h1>
</div>
)
}
export default Category;
'I even tried mentioning 2nd route as normal route (Without Param-route). No luck'
Try this:
import { Switch, Route } from 'react-router-dom';
//your code
return (
<Switch>
<Route exact path="/shop" component={CollectionPreview} />
<Route path="/shop/:categoryId" component={Category} />
</Switch>
);
For more details about when to use Switch, refer this: here
you can try with useParams() hooks. like below
import React from "react";
import { useParams } from 'react-router-dom';
import "./category-style.css";
const Category = () => {
const {categoryId} = useParams();
return(
<div className="Test">
<h1>Test</h1>
</div>
)
}
export default Category;