My links in the following code are not working. I'm a beginner and I'm not sure on where the issue is.
Do you have any tips on how to debug that?
Thank you,
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import {fetchItems} from './actions/items';
import { connect } from 'react-redux';
import './App.css';
import Home from './components/Home.js'
import Additem from './components/Additem'
import Mybag from './components/Mybag.js'
import About from './components/About.js'
import ItemShow from './components/ItemShow.js'
import NavigationBar from './components/NavigationBar.js'
class App extends Component {
constructor(props){
super(props)
}
componentDidMount(){
this.props.fetchItems();
}
render() {
console.log("itemList: ", itemList)
const itemList = this.props.items
return (
<div className="App">
<NavigationBar />
<React.Fragment>
<Route exact path='/' render={routerProps => <Home {...routerProps} items={itemList}/>} />
<Route exact path={`/items/:itemID`} component={ItemShow} />
<Route exact path="/my_bag" component={Mybag} />
<Route exact path="/add_item" component={Additem} />
<Route exact path="/about" component={About} />
</React.Fragment>
</div>
)
}
}
const mapStateToProps = state => {
return {
items: state.items
}
}
const mapDispatchToProps = dispatch => {
return {
fetchItems: (items) => dispatch(fetchItems(items)),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
I used to have a component in charge of fetching my items in the DB and load them. It was working but refactored to include the fetch as a redux action and since then, it is not working anymore.
Please let me know if you have any tips.
Thank you!
Wrap your connected component with react-router's withRouter function:
// Adding the imports just for clarity.
import { connect } from "react-redux";
import { compose } from "redux";
import { withRouter } from "react-router-dom";
// compose-style
compose(
withRouter,
connect(...)
)(YourComponent);
// Without compose
withRouter(connect(...))(Your component);
For more information: withRouter API
sn42 is right. But I prefer to export the container with withRouter function rather than using compose
export default withRouter((connect(mapStateToProps, mapDispatchToProps)(App)));
Related
I'm been trying to learn React by following some Coursera course and just got to Redux but the React they have been using, and other packages are outdated(Usually deprecated,He also uses v5 of react-router-dom and Redux(createStore)), so I've been trying my best to find the replacements in the new versions. I have tried looking for a way to fix it but most information I find says that it's better to use functional components with hooks, but this course doesn't have anything about hooks.
Below is my main component, the course used withRouter but that was removed.
import React, { Component } from 'react';
import Home from './HomeComponent';
import Menu from './MenuComponent';
import DishDetail from './DishDetailComponent';
import About from './AboutComponent';
import Contact from './ContactComponent';
import Header from './HeaderComponent';
import Footer from './FooterComponent';
import {Routes, Route, Navigate, useParams, useLocation, useNavigate} from 'react-router-dom';
import {connect} from 'react-redux';
const mapStateToProps = state => {
return{
dishes: state.dishes,
commets: state.comments,
promotions: state.promotions,
leaders : state.leaders
}
}
class Main extends Component{
constructor(props){
super(props);
}
render(){
console.log("this is props xd "+ JSON.stringify(this.props))
const HomePage = () => {
return(
<Home dish={this.props.dishes.filter((dish)=>dish.featured)[0]}
promotions={this.props.promotions.filter((promotion)=> promotion.featured)[0]}
leader={this.props.leaders.filter((leader)=>leader.featured)[0]}
/>
);
};
const DishWithId = () =>{
//in V6 of reach route dom, we need to use useParams() to get parms zz
const match = useParams();
return(
<DishDetail dish={this.props.dishes.filter((dish)=>{
if(dish.id=== parseInt(match.dishId, 10)){
return true;
}
return false;
})[0]}
comments={this.props.comments.filter((comment)=> comment.dishId === parseInt(match.dishId, 10))}
/>
);
}
return (
<div >
<Header />
<Routes>
<Route path="/home" element={<HomePage />} />
{/* this path should match exactly to the route when using exact */}
<Route exact path="/menu" element={<Menu dishes={this.props.dishes}/>} />
<Route path="/menu/:dishId" element={<DishWithId />} />
<Route exact path="/contactus" element={<Contact />}/>
<Route exact path="/aboutus" element={<About leaders={this.props.leaders}/>}/>
<Route path="/*" element={<Navigate replace to="/home" />}/>
</Routes>
<Footer/>
</div>
);
}
}
export default connect(mapStateToProps)(Main);
Below is my configureStore and reducer
import {configureStore} from '#reduxjs/toolkit';
import { Reducer, initialState } from './reducer';
export const Store = configureStore({
reducer:{
todos: Reducer
},
initialState: initialState
});
Reducer
import {DISHES} from '../shared/dishes';
import { COMMENTS } from '../shared/comments';
import { LEADERS } from '../shared/leaders';
import { PROMOTIONS } from '../shared/promotions';
export const initialState = {
dishes: DISHES,
comments: COMMENTS,
promotions: PROMOTIONS,
leaders: LEADERS
};
export const Reducer = (state = initialState, action) =>{
return state;
}
This is a common issue with the Coursera React course, where all exercises have been designed using older package versions and lots of stuff has been deprecated, replaced or removed altogether (doing that now and experiencing the same pain). The specific issue - find an alternative for the class component export that uses the withRouter method that is removed in v6 and higher. I searched around for a bit and found the solution in a post:
withRouter is not exported from react-router-dom
We can get it to work by defining our our own withRouter function and use it the same way the original function was supposed to be used.
import {Routes, Route, Navigate, useLocation, useNavigate, useParams} from 'react-router-dom'
import { connect } from 'react-redux'
const mapStateToProps = reduxStoreState => {
return({
dishes: reduxStoreState.dishes,
comments: reduxStoreState.comments,
leaders: reduxStoreState.leaders,
promotions: reduxStoreState.promotions
})
}
class MainAppManager extends Component {
...
}
const withRouter = Component => {
const ComponentWithRouterProp = props => {
let location = useLocation()
let navigate = useNavigate()
let params = useParams()
return (
<Component {...props} router={{ location, navigate, params }}/>
)
}
return ComponentWithRouterProp
}
export default withRouter(connect(mapStateToProps)(MainAppManager))
I'm working on a scenario where I want to open a particular URL in new tab when user clicks on particular button. I've used window.open("/itemPage", '_blank'); for opening new tab. but I'm not able to pass data to particular component through react router.
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import Home from './Home';
import ItemPageComponent from './ItemPageComponent';
import history from '../history';
import { connect, Provider } from 'react-redux';
class RouterComponent extends React.Component {
render() {
console.log("CCTV cameraInfoFrame:: " + this.props.item.name);
return (
<div>
<Router history={history}>
<div>
<Switch>
<Route exact
path="/"
component={Home}
/>
<Route exact
path="/itemPage"
component={<ItemPageComponent data={ this.props.item} />}
/>
</Switch>
</div>
</Router>
</div>
);
}
}
const mapStateToProps = (state) => ({
item: state.PopoutReducer.itemDetailsState
});
const RouterContainer = connect(
mapStateToProps,
)(RouterComponent);
export default RouterContainer;
Can anyone help me out for this?
Thanks in Advance.
My react app is throwing the following error and as I have only a couple of weeks in react and even less in redux and I don't know how to overpass it. I tried different answers from the web but didn't manage to make it work. Maybe some of you can help.
The error:
Passing redux store in props has been removed and does not do anything. To use a custom Redux store for specific components, create a custom React context with React.createContext(), and pass the context object to React-Redux's Provider and specific components like: . You may also pass a {context : MyContext} option to connect
The code looks like this
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css'
import 'font-awesome/css/font-awesome.css'
import 'bootstrap-social/bootstrap-social.css'
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
App.js
import React, { Component } from 'react';
import Main from './components/MainComponent';
import './App.css';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { ConfigureStore } from './redux/configureStore';
const store = ConfigureStore();
class App extends Component {
render() {
return (
<Provider store={store}>
<BrowserRouter>
<div>
<Main />
</div>
</BrowserRouter>
</Provider>
);
}
}
export default App;
Reducer.js:
import { DISHES } from '../shared/dishes';
import { COMMENTS } from '../shared/comments';
import { PROMOTIONS } from '../shared/promotions';
import { LEADERS } from '../shared/leaders';
export const initialState = {
dishes: DISHES,
comments: COMMENTS,
promotions: PROMOTIONS,
leaders: LEADERS
};
export const Reducer = (state = initialState, action) => {
return state;
};
configureStore.js
import { createStore } from 'redux';
import { Reducer, initialState } from './reducer';
export const ConfigureStore = () => {
const store = createStore(
Reducer, // reducer
initialState, // our initialState
);
return store;
}
MainComponent.js
import React, { Component } from 'react';
import Menu from './MenuComponent';
import Header from './HeaderComponent'
import Footer from './FooterComponent'
import DishDetail from './DishdetailComponent'
import About from './AboutComponent';
import Home from './HomeComponent';
import Contact from './ContactComponent';
import { Switch, Route, Redirect, withRouter } from 'react-router-dom'
import { connect } from 'react-redux';
const mapStateToProps = state => {
return {
dishes: state.dishes,
comments: state.comments,
promotions: state.promotions,
leaders: state.leaders
}
}
class Main extends Component {
render() {
const HomePage = () => {
return (
<Home
dish={this.props.dishes.filter((dish) => dish.featured)[0]}
promotion={this.props.promotions.filter((promo) => promo.featured)[0]}
leader={this.props.leaders.filter((leader) => leader.featured)[0]}
/>
);
}
const DishWithId = ({ match }) => {
return (
<DishDetail dish={this.props.dishes.filter((dish) => dish.id === parseInt(match.params.dishId, 10))[0]}
comments={this.props.comments.filter((comment) => comment.dishId === parseInt(match.params.dishId, 10))} />
);
};
return (
<div>
<Header />
<div>
<Switch>
<Route path='/home' component={HomePage} />
<Route exact path='/aboutus' component={() => <About leaders={this.props.leaders} />} />} />
<Route exact path='/menu' component={() => <Menu dishes={this.props.dishes} />} />
<Route path='/menu/:dishId' component={DishWithId} />
<Route exact path='/contactus' component={Contact} />} />
<Redirect to="/home" />
</Switch>
</div>
<Footer />
</div>
);
}
}
export default withRouter(connect(mapStateToProps)(Main));
The package that you are using for handling forms- 'react-redux-form' is currently facing issues with React 6. It is currently in maintenance mode.
You can either use alternatives like Formik or downgrade to a stable version of 'React' and 'react-native-form'.
Hope this helps :)
I'm having an issue in where by I switch routes, and the value of a property in my store is reverting back to it's original state. I'm using react 16 with react router v4.
I'm also noticing that the entire App component rerenders when I change routes. That seems over the top. It's running mapStateToProps and mapDispatchToProps every time. I'm noticing the state passed into mapStateToProps is always empty too.
I'm very puzzled.
main file
import React from 'react';
import { render } from 'react-dom';
import { connect } from 'react-redux';
//install routing deps
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store'
import App from './components/App';
render(
<Provider store={store}>
<BrowserRouter>
<App/>
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
store
import { createStore, compose, applyMiddleware} from 'redux';
import rootReducer from './reducers/index';
const defaultState = { count: 0 };
const enhancers = compose(
window.devToolsExtension ? window.devToolsExtension() : f => f,
);
const store = createStore(rootReducer, defaultState, enhancers);
//adds hot reload for changes to reducer
if(module.hot){
module.hot.accept('./reducers', ()=>{
const nextRootReducer = require(`./reducers/index`).default;
store.replaceReducer(nextRootReducer);
});
};
export default store;
App component
import React, { Component } from 'react';
import { Route, Switch, Redirect, Link } from 'react-router-dom';
import { BrowserRouter, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actionCreators from '../actions/actionCreators';
class App extends Component {
constructor() {
super();
};
render() {
return (
<div>
main
<a href='/info'>info</a>
<Switch>
<Route exact path="/" render={() => <h1>kawaii world</h1>} />
<Route exact path="/info" render={() => <h1>v kawaii world ;)</h1>} />
</Switch>
</div>
);
};
};
function mapStateToProps(state) {
return {
count: state.count
};
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch);
};
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
If you make use of tag a literally you are saying that you are willing to go to another page but in react apps that's not the case. In react you navigate from one component to another.
So to fix your issue you need to do this:
import { BrowserRouter, Link, withRouter } from 'react-router-dom';
class App extends Component {
render() {
return (
<div>
<Link to="/">Main</Link>
<Link to="/info">Info</Link>
<Switch>
<Route exact path="/" render={() => <h1>kawaii world</h1>} />
<Route exact path="/info" render={() => <h1>v kawaii world ;)</h1>} />
</Switch>
</div>
);
};
};
I am trying to render a specific component inside of another component based on React, React-Router v4, and Redux in my main 'panel' wrapped in a fixed header and sidebar component.
For example when I select an item from the sidebar, I to render the Detail panel and and load the details based on the id, like: <Route path='/item/:id' component={ItemDetail} />
routes.js
import React, { Component } from 'react';
import { RouteHandler, Switch, Route, DefaultRoute } from 'react-router';
import App from './containers/App';
import Login from './containers/Login';
import LobbyDetail from './components/LobbyDetail';
export default (
<Switch>
<Route exact path="/" component={App} />
<Route exact path="/login" component={Login} />
</Switch>
);
app.js:
import React, { Component } from 'react'
import { Router, Route, Link } from 'react-router'
import { connect } from 'react-redux'
import PropTypes from 'prop-types';
import auth from '../actions/auth';
import Sidebar from '../Components/Sidebar'
class App extends Component {
static propTypes = {
};
/**
*
*/
render() {
const { ... } = this.props
return (
<div className="container-fluid">
<div className="row">
{* I WANT TO RENDER DYNAMIC COMPONENT HERE *}
</div>
<Sidebar currentUser={currentUser}
logout={logout}
/>
</div>
);
}
}
// ...
export default connect(mapStateToProps, mapDispatchToProps)(App)
index.js (basically main app):
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import { createMemoryHistory } from 'history';
import routes from './routes';
import configureStore from './store/store.js';
import { AppContainer } from 'react-hot-loader';
const syncHistoryWithStore = (store, history) => {
const { routing } = store.getState();
if (routing && routing.location) {
history.replace(routing.location);
}
};
const initialState = {};
const routerHistory = createMemoryHistory();
const store = configureStore(initialState, routerHistory);
syncHistoryWithStore(store, routerHistory);
const rootElement = document.querySelector(document.currentScript.getAttribute('data-container'));
const render = () => {
ReactDOM.render(
<AppContainer>
<Provider store={store}>
<ConnectedRouter history={routerHistory}>
{routes}
</ConnectedRouter>
</Provider>
</AppContainer>,
rootElement
);
}
render();
if (module.hot) { module.hot.accept(render); }
What you're looking for is parameterized routing. Make a <Route/> like the following: <Route path='/item/:id' component={ MyComponent } />.
Now in MyComponent you can use the value of props.match.params.id to conditionally render, or if you're trying to load async data based on the value of :id; You can use the componentWillReceiveProps life cycle method and dispatch an action based on the value of this.props.match.params.id.
Note: <Link to='/item/some-item'/> will set the value of match.params.id to 'some-item'.