i working by react js router (react-router-dom v4.2) and Redux together and have strange varios problem
first i say i successfully used and run this but the problems
when i use the root route as first rote in route list router stop working!!
but when i use '/' route as last route everything is ok
<Switch>
<Route path="/blog" component={Blog} />
<Route path="/users/" component={Users} />
<Route path="/" component={Home} axact />
</Switch>
when i create routes as external component and import it to app routes not work
this is my route.js codes
import React, { Component } from 'react';
import { Switch, Route } from "react-router-dom";
// import Components
import Home from './components/Home'
import Blog from './components/blog/Blog'
import Users from './components/users/Users'
class router extends Component {
render() {
return (
<div>
<Switch>
<Route path="/" component={Home} axact />
<Route path="/blog" component={Blog} />
<Route path="/users/" component={Users} />
</Switch>
</div>
);
}
}
export default router;
this is my App.js codes:
import React, { Component } from 'react';
import { getUsers } from './store/actions'
import { connect } from 'react-redux'
import { withRouter } from "react-router-dom";
import Nav from './components/navigation/Nav';
import axios from 'axios';
const userApi = "https://jsonplaceholder.typicode.com/users"
class App extends Component {
componentWillMount() {
axios.get(userApi)
.then(response => {
let users = response.data
this.props.getUserList(users)
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div className="container">
<Nav />
<Router />
</div>
);
}
}
const mapDispatchToProps = dispatch => ({ getUserList: (api) => dispatch(getUsers(api)) })
export default withRouter(connect(null, mapDispatchToProps)(App));
when i use this codes everything is ok
import React, { Component } from 'react';
import { getUsers } from './store/actions'
import { connect } from 'react-redux'
import { Switch, Route, withRouter } from "react-router-dom";
import Home from './components/Home'
import Blog from './components/blog/Blog'
import Users from './components/users/Users'
import Nav from './components/navigation/Nav';
import axios from 'axios';
const userApi = "https://jsonplaceholder.typicode.com/users"
class App extends Component {
componentWillMount() {
axios.get(userApi)
.then(response => {
let users = response.data
this.props.getUserList(users)
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div className="container">
<Nav />
<Switch>
<Route path="/blog" component={Blog} />
<Route path="/users/" component={Users} />
<Route path="/" component={Home} axact />
</Switch>
</div>
);
}
}
const mapDispatchToProps = dispatch => ({ getUserList: (api) => dispatch(getUsers(api)) })
export default withRouter(connect(null, mapDispatchToProps)(App));
Related
I am learning React and while creating the project the mentor used the products_context.js and added some reducers to it, but then he surrounded the tag with this component's tag. I am trying to understand why did he do that in the main index.js and not in App.js file?
products_context.js
import axios from 'axios'
import React, { useContext, useEffect, useReducer } from 'react'
import reducer from '../reducers/products_reducer'
import { products_url as url } from '../utils/constants'
import {
SIDEBAR_OPEN,
SIDEBAR_CLOSE,
GET_PRODUCTS_BEGIN,
GET_PRODUCTS_SUCCESS,
GET_PRODUCTS_ERROR,
GET_SINGLE_PRODUCT_BEGIN,
GET_SINGLE_PRODUCT_SUCCESS,
GET_SINGLE_PRODUCT_ERROR,
} from '../actions'
const initialState = {
isSidebarOpen: false,
}
const ProductsContext = React.createContext()
export const ProductsProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState)
const openSidebar = () => {
dispatch({ type: SIDEBAR_OPEN })
}
const closeSidebar = () => {
dispatch({ type: SIDEBAR_CLOSE })
}
return (
<ProductsContext.Provider value='products context'>
{children}
</ProductsContext.Provider>
)
}
// make sure use
export const useProductsContext = () => {
return useContext(ProductsContext)
}
index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import App from './App'
import { ProductsProvider } from './context/products_context'
import { FilterProvider } from './context/filter_context'
import { CartProvider } from './context/cart_context'
import { UserProvider } from './context/user_context'
import { Auth0Provider } from '#auth0/auth0-react'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<ProductsProvider>
<App />
</ProductsProvider>
)
App.js
import React from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import { Navbar, Sidebar, Footer } from './components'
import {
Home,
Products,
SingleProduct,
About,
Cart,
Checkout,
Error,
AuthWrapper,
PrivateRoute,
} from './pages'
function App() {
return (
<Router>
<Navbar />
<Sidebar />
<Switch>
<Route exact path='/'>
<Home />
</Route>
<Route exact path='/about'>
<About />
</Route>
<Route exact path='/cart'>
<Cart />
</Route>
<Route exact path='/products'>
<Products />
</Route>
<Route exact path='/products/:id' children={<SingleProduct />} />
<Route exact path='/checkout'>
<Checkout />
</Route>
<Route exact path='*'>
<Error />
</Route>
</Switch>
<Footer />
</Router>
)
}
export default App
I am just trying to uderstand the reason for this code structure.
app.js file code i want to convert it
import Toolbar from "./components/Toolbar";
// import Iqac from "./components/Iqac/iqac";
import React from "react";
import "./styles.css";
import SideDrawer from "./components/sidemenu/SideDrawer";
import BackDrop from "./components/backdrop/BackDrop";
import { Route, Router, Routes } from "react-router-dom";
class App extends React.Component {
state = {
};
drawerToggleClickHandler = () => {
this.setState(prevState => {
return { sideDrawerOpen: !prevState.sideDrawerOpen };
});
};
backDropClickHandler = () => {
this.setState({ sideDrawerOpen: false });
};
render() {
// let sideDrawer;
let backdrop;
if (this.state.sideDrawerOpen) {
// sideDrawer = <SideDrawer />;
backdrop = <BackDrop click={this.backDropClickHandler} />;
}
return (<>
<div className="tool">
<Toolbar drawerToggleClickHandler={this.drawerToggleClickHandler} />
<SideDrawer show={this.state.sideDrawerOpen} />
{backdrop}
</div>
</>
);
}
}
export default App;
i have tried to change also i want to impliment react router dom v6 so that is why is need to do this and i don't know how to do in react-class based component
import Toolbar from './components/Toolbar'
import Footer from './components/Footer'
import Home from './Pages/Home'
import { useState } from "react";
import About from "./Pages/About"
import {
BrowserRouter as Router,
Route,
Routes
} from "react-router-dom";
const App = () => {
const [state, setstate] = useState({
sideDrawerOpen: false
});
return (
<>
<Router>
<Toolbar />
<Routes>
<Route path='/' element={<Home />}> </Route>
<Route path='/about/*' element={<About />}> </Route>
</Routes>
</Router>
<Footer />
</>
);
}
export default App;
i want to use react router dom and i thing v6 does't work with class
component
please help me resolve this issue i need to lot of your support thankyou so much in advance for the help
Try to change your code like this:
import Toolbar from './components/Toolbar';
import Footer from './components/Footer';
import Home from './Pages/Home';
import { useState } from 'react';
import About from './Pages/About';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
const App = () => {
const [sideDrawerOpen, setSideDrawerOpen] = useState(false);
const drawerToggleClickHandler = () => {
setSideDrawerOpen((prevState) => !prevState);
};
const backDropClickHandler = () => {
setSideDrawerOpen(false);
};
return (
<div className='tool'>
<Toolbar drawerToggleClickHandler={drawerToggleClickHandler} />
<SideDrawer show={sideDrawerOpen} />
{sideDrawerOpen && <BackDrop click={backDropClickHandler} />}
<Router>
<Toolbar />
<Routes>
<Route path='/' element={<Home />}>
{' '}
</Route>
<Route path='/about/*' element={<About />}>
{' '}
</Route>
</Routes>
</Router>
<Footer />
</div>
);
};
export default App;
Goal:
When you write url "https://react-router-with-params-aq6utk.stackblitz.i/test" I would like to display the page test.
Problem:
Is it possble to retrieve the value 'test' and use it at app.js?
Today it doesn't work.
Info:
*Newbie in reactjs
Stackblitz:
https://stackblitz.com/edit/react-uaofyx?file=src%2FApp.js
app.js
import React, { Component } from 'react';
import { HomeComponent } from './Containers/HomeComponent';
import DashboardComponent from './Containers/DashboardComponent';
import ContactComponent from './Containers/ContactComponent';
import { Switch, Route, Link } from 'react-router-dom';
class App extends Component {
constructor() {
super();
this.state = {
name: 'React',
};
}
render() {
console.log(this.props.id);
console.log(this.props);
if (this.props.id === 'test') {
return (
<div>
<Switch>
<Route path="/test" exact component={ContactComponent} />
</Switch>
</div>
);
} else {
return (
<div>
<Switch>
<Route
path="/dashboard/:id"
render={(props) => (
<DashboardComponent {...props} isAuthed={true} />
)}
/>
<Route path="" exact component={HomeComponent} />
</Switch>
</div>
);
}
}
}
export default App;
ContactComponent.js
import React from 'react';
export const ContactComponent = ({ value }) => {
const name = 'CONTACT';
return <h1>{name}</h1>;
};
DashboardComponent.js
import React, { Component } from 'react';
class DashboardComponent extends Component {
constructor(props) {
super(props);
console.log(this.props.match.params.id);
}
render() {
return <div>Hello from dashboard.. ffff</div>;
}
}
export default DashboardComponent;
HomeComponent.js
import React from 'react';
export const HomeComponent = ({ value }) => {
const name = 'rajesh';
return <h1>{name}</h1>;
};
There are some issues with the implementaion of Route. also, you export the ContactComponent without default but you used it in App.js with the default import statement.
The working code:
import React, { Component } from 'react';
import { HomeComponent } from './Containers/HomeComponent';
import DashboardComponent from './Containers/DashboardComponent';
import { ContactComponent } from './Containers/ContactComponent';
import { Switch, Route, Link, BrowserRouter as Router } from 'react-router-dom';
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route path="/test" exact component={ContactComponent} />
<Route
path="/dashboard/:id"
component={(props) => <DashboardComponent {...props} isAuthed={true} />}
/>
<Route path="" exact component={HomeComponent} />
</Switch>
</Router>
);
}
}
export default App;
check the live version on stackblitz
Explanation:
If you export a variable with the default keyword, so you need to import it without {}
const first = 'first'
const second = 'second'
export first
export default second
Now in usage:
import second, {first} from 'myVariables';
Also, your route configuration with react-router-dom will look like this:
<BrowserRouter>
<Switch>
<Route path="/" exact={true} component={Home} />
<Route path="/about" exact={true} component={About} />
<Route path="/contact" exact={true} component={Contact} />
// rest of the routes ...
</Switch>
</BrowserRouter>
Note: Your App.js component is the root component so there aren't any props with it.
I'm facing a problem with react-router-dom. I'm trying to use history.push for navigating after an action conducted. but the problem is createBrowserHistory from history is updating the urls but components are not re-rendering. I've used every solution from https://stackoverflow.com/. But it's still not working as expected.
However I found a reason behind it. As my components are wrapped with connect function connect is preventing the re-render. And there was a solution too, wrap the connect function with withRouter. I tried it too. But it's not working.
Here is My App.js
import React, { Component } from "react";
import { Router, Route } from "react-router-dom";
import history from "../history"
import Navbar from "./Navbar";
import LogIn from "./LogIn";
import StreamCreate from "./streams/StreamCreate";
import StreamDelete from "./streams/StreamDelete";
import StreamEdit from "./streams/StreamEdit";
import StreamList from "./streams/StreamList";
import StreamShow from "./streams/StreamShow";
import Profile from "./streams/Profile";
class App extends Component {
render() {
return (
<div>
<Router history={history}>
<div>
<Navbar />
<Route path="/" exact component={StreamList} />
<Route path="/streams/new" exact component={StreamCreate} />
<Route path="/streams/delete" exact component={StreamDelete} />
<Route path="/streams/edit" exact component={StreamEdit} />
<Route path="/streams/show" exact component={StreamShow} />
<Route path="/login" exact component={LogIn} />
<Route path="/my-streams" exact component={Profile} />
</div>
</Router>
</div>
);
}
}
export default App;
Here is the history.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
Action Creator:
import Streams from "../API/Streams";
import history from "../history";
export const createStreams = (formData) => async (dispatch, getState) => {
const { userId } = getState().auth;
const response = await Streams.post("/streams", { ...formData, userId });
dispatch({ type: "CREATE_STREAM", payload: response.data });
history.push("/")
};
I am trying to make a PrivateRoute component for react. Here is my higher order component. Can you tell me what is the problem with this.
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
export default ({ component: Component, ...rest }) => {
class PrivateRoute extends React.Component {
render() {
console.log("This is private route called");
if (this.props.profile) {
return (
<Route
{...rest}
render={props =>
this.props.profile.loggedIn === true ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
}
}
}
const mapStateToProps = state => ({
profile: state.profile
});
return connect(mapStateToProps)(PrivateRoute);
};
Here's how you can accomplish a protected route via a protected route component.
Working example: https://codesandbox.io/s/yqo75n896x
containers/RequireAuth.js
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import ShowPlayerRoster from "../components/ShowPlayerRoster";
import ShowPlayerStats from "../components/ShowPlayerStats";
import Schedule from "../components/Schedule";
const RequireAuth = ({ match: { path }, isAuthenticated }) =>
!isAuthenticated ? (
<Redirect to="/signin" />
) : (
<div>
<Route exact path={`${path}/roster`} component={ShowPlayerRoster} />
<Route path={`${path}/roster/:id`} component={ShowPlayerStats} />
<Route path={`${path}/schedule`} component={Schedule} />
</div>
);
export default connect(state => ({
isAuthenticated: state.auth.isAuthenticated
}))(RequireAuth);
routes/index.js
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import Home from "../components/Home";
import Header from "../containers/Header";
import Info from "../components/Info";
import Sponsors from "../components/Sponsors";
import Signin from "../containers/Signin";
import RequireAuth from "../containers/RequireAuth";
import rootReducer from "../reducers";
const store = createStore(rootReducer);
export default () => (
<Provider store={store}>
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/info" component={Info} />
<Route path="/sponsors" component={Sponsors} />
<Route path="/protected" component={RequireAuth} />
<Route path="/signin" component={Signin} />
</Switch>
</div>
</BrowserRouter>
</Provider>
);
Or, if you want something that wraps all routes (instead of having to specify a protected route component). Then you can do something like the below.
Working example: https://codesandbox.io/s/5m2690nn6n
components/RequireAuth.js
import React, { Component, Fragment } from "react";
import { withRouter } from "react-router-dom";
import Login from "./Login";
import Header from "./Header";
class RequireAuth extends Component {
state = { isAuthenticated: false };
componentDidMount = () => {
if (!this.state.isAuthenticated) {
this.props.history.push("/");
}
};
componentDidUpdate = (prevProps, prevState) => {
if (
this.props.location.pathname !== prevProps.location.pathname &&
!this.state.isAuthenticated
) {
this.props.history.push("/");
}
};
isAuthed = () => this.setState({ isAuthenticated: true });
unAuth = () => this.setState({ isAuthenticated: false });
render = () =>
!this.state.isAuthenticated ? (
<Login isAuthed={this.isAuthed} />
) : (
<Fragment>
<Header unAuth={this.unAuth} />
{this.props.children}
</Fragment>
);
}
export default withRouter(RequireAuth);
routes/index.js
import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Home from "../components/Home";
import Players from "../components/Players";
import Schedule from "../components/Schedule";
import RequireAuth from "../components/RequireAuth";
export default () => (
<BrowserRouter>
<RequireAuth>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/players" component={Players} />
<Route path="/schedule" component={Schedule} />
</Switch>
</RequireAuth>
</BrowserRouter>
);
Or, if you want something a bit more modular, where you can pick and choose any route, then you can create a wrapper HOC. See this example (while it's written for v3 and not for authentication, it's still the same concept).
It looks like your render function's only return is inside of an if block, so its returning null. You need to fix the logic to just return the Route and make profile a required prop in your proptypes check instead of using an if block.
PrivateRoute.propTypes = {
profile: PropTypes.object.isRequired
};