It seems like react router does not work with redux, clicking the link in App component successfuly add '/search' to the URL but it does not navigate to the search page, the navigation only happens after i refresh the page not after clicking the link, so what is the problem here??
Here are my two components
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import * as BooksAPI from './BooksAPI';
import registerServiceWorker from './registerServiceWorker';
import { createStore, applyMiddleware } from 'redux';
import { bookReducer } from './reducers/BookReducer';
import thunk from 'redux-thunk';
import {BrowserRouter as Router} from 'react-router-dom';
const middleware = [thunk];
const store = createStore(bookReducer, [], applyMiddleware(...middleware));
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
App.js
import React, { Component } from 'react';
import { connect} from 'react-redux'
import BookShelf from './components/BookShelf'
import AllShelves from './components/AllShelves'
import Header from './components/Header';
import SearchPage from './components/SearchPage';
import * as BooksAPI from './BooksAPI';
import { Route } from 'react-router-dom';
import { Link } from 'react-router-dom';
import './App.css';
class App extends Component {
componentWillMount() {
this.props.fetchBooks();
}
render() {
console.log(this.props.books)
return (
<div className="App">
<Header />
<Route exact path="/" render={(props) => <AllShelves />} />
<Route path="/search" render={(props) => <SearchPage />} />
<div className="open-search">
<Link to="/search" />
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
books: state
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchBooks: () => {
BooksAPI.getAll().then(books => dispatch({
type: 'FETCH_BOOKS',
books
}))
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
So why clicking link doesn't cause navigation to the search page and only add '/search' to the URL.
You might need to apply withRouter to make it work.
import {withRouter , BrowserRouter as Router} from 'react-router-dom';
// your code here
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
I recommend to to read the official documentation on how to integrate React Router with Redux
https://reacttraining.com/react-router/web/guides/redux-integration
Related
There is a problem navigating to the application page. When clicked, the url changes, but the content does not change. Wrapped connect in withRouter but doesn't help. I'm using webpack 5, but I haven't configured anything for routing. Where could the problem be with this implementation?
App.js
import logo from './logo.svg';
import history from "./utils/history";
import './App.css';
import AuthLayout from "./containers/auth-controller";
import Menu from './components/menu';
import {
Router,
Switch,
Route
} from "react-router-dom";
import routes from './routes'
function App() {
return (
<Router history={history}>
<AuthLayout>
<div className="App">
<Menu/>
<div className="page">
{routes}
</div>
</div>
</AuthLayout>
</Router>
);
}
export default App;
index.js
import history from "./utils/history";
let React = require('react');
let ReactDOM = require('react-dom');
import './index.css';
import 'antd/dist/antd.css';
import App from './App';
import {Provider} from "react-redux";
import store from "./store";
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App/>
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
Route.js
import React from 'react';
import { withRouter } from 'react-router-dom';
import { Route } from 'react-router-dom';
import Component from './component';
export default <Route exact path="/tests" component={Component} />;
Routes.js
import React from 'react';
import { Switch, Redirect } from 'react-router-dom';
import * as Pages from './pages';
export default (
<Switch>
{ Object.values(Pages) }
</Switch>
);
component.js
import React from 'react';
import {connect} from "react-redux";
import {withRouter} from "react-router-dom";
import history from "./history";
class Component extends React.Component {
state = {
username: undefined,
password: undefined
}
onRedirect = () => {
history.push("/home");
}
render() {
const {token} = this.props;
return (
<div className="auth">
<a onClick={this.onRedirect}>Redirect</a>
</div>
)
}
}
function mstp(state) {
return {
...
}
};
function mdtp(dispatch) {
return {
...
}
}
}
export default withRouter(connect(mstp, mdtp)(Component));
export default withRouter(connect(mstp, mdtp)(Component));
history.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// import browserRoute
import { BrowserRouter, Switch, Route, Link } from 'react-router-dom'
// redux
import Todo from './todo/Todo';
import Login from './todo/Login';
import Home from './todo/Home';
import Callender from './Callender/Callender'
import WhetherData from './Callender/CallenderComponent'
import { localstoreExport } from './index';
export default class App extends Component {
render() {
return (
<BrowserRouter>
< Switch>
<Route path="/todo">
<Todo />
</Route>
<Route path="/login">
<Login />
</Route>
<Route path ="/callender">
<Callender />
</Route>
<Route path="/climateshow" component ={WhetherData}/>
<Route exact path="/" component={Home}/>
</Switch>
</BrowserRouter>
</Provider>
)
}
}
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// Redux
import { createStore,combineReducers,applyMiddleware,compose } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
// import reducer
import todoReducer from './store/reducers/rootReducer';
import whetherReducer from './store/reducers/callender'
// combine the Reducer
const rootReducer = combineReducers({
todoReducer,
whetherReducer
})
// chrome extension helper
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// create a store
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));
export const localstoreExport = store;
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
Callender.js
import React, { Component } from 'react';
import { DatePicker, DatePickerInput } from 'rc-datepicker';
import 'rc-datepicker/lib/style.css';
import axios from 'axios'
import { connect } from 'react-redux';
// redux components
import { getDataFromApi } from '../store/actions/callender'
class Callender extends Component {
state = {
totalDate:''
}
// These is the complete code for getting the response from version 2 of api
onChange = (event) =>{
console.log(event);
this.setState({
totalDate:event
})
this.props.getWhetherData()
{console.log(this.props.whetherData)}
}
render() {
const date = '2015-06-26';
return (
<div>
<DatePicker onChange={this.onChange} value={date} />
{this.props.whetherData? console.log(this.props.history): null}
</div>
)
}
}
const mapStateToProps = state =>{
return {
whetherData: state.whetherReducer.whetherData
}
}
const mapDispatchToProps = dispatch =>{
return {
getWhetherData : () => dispatch(getDataFromApi())
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Callender);
1)In the following code I have written my Routes, in App.js file and created store in Index.js
2) In Callender.js i want to push my route to whether data end Point so i am trying to see the this.props.history it is showing undefined
3) so i tried to see my props by this.props Now it is showing me the redux props so i realized that
my router props are getting overridden by redux props
4) how to use history push while using redux
You can wrap your component with withRouter.
import { withRouter } from "react-router";
export default connect(mapStateToProps,mapDispatchToProps)(withRouter(Callender));
You can find detailed example here.
I am new to React Js.
Everything works fine until I am trying to do action creator in ReactJs.
I know that there are other questions(posts) related to the title,however , I cannot find to solve my problem. Please Help me!
Here is my index.js
import 'materialize-css/dist/css/materialize.min.css';
import React from 'react';
import ReactDOM from 'react-dom';
import { provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import reduxThunk from 'redux-thunk';
import App from './components/App';
import reducers from './reducers';
import connect from 'react-redux/lib/connect/connect';
// create reducer
const store = createStore(reducers, {}, applyMiddleware(reduxThunk));
// Render the App in the HTML root element which is inside public foler
ReactDOM.render(
//Provier is to handle redux store actions
<provider store = { store }><App/></provider> ,
document.querySelector('#root')
);
Here is my App.Js
import React,{ Component } from 'react';
import { BrowserRouter, Route} from 'react-router-dom';
import { connect } from 'react-redux';
import * as actions from '../actions';
import Header from './Header';
const dashboard = () => <h2>DashBoard</h2>
const surveyNew = () => <h2>SurveyNew</h2>
const landing = () => <h2>Landing</h2>
class App extends Component {
//Call Action Creaters before View is Up
componentDidMount() {
this.props.fetchUser();
}
render () {
return (
<div className="container">
<BrowserRouter>
<div>
<Header/>
<Route exact path="/" component = {landing} />
<Route exact path = "/surveys" component = {dashboard}/>
<Route path = "/surveys/new" component = {surveyNew} />
</div>
</BrowserRouter>
</div>
);
}
};
export default connect(null, actions)(App);
Any help would be appreciated, Sirs. Thank You
It is with a capital "p" in "Provider". Try like that:
import { Provider } from 'react-redux';
...
<Provider store={store}><App/></Provider> ,
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'.
I am using react-router 4 with react-redux. but now I am not able to render any page. I am getting 404 while hitting URL. but console is not showing any error. may be I have colluded something with react-router version 3 but not able to get it what? one more thing here is that my one reducers is being called while store registration though I am not adding reducers in it.and more thing is IndexRoute deprecated in v4?
here is my config.js
import React from 'react'
import { render } from 'react-dom'
import { createStore, applyMiddleware,compose } from 'redux'
import { Provider } from 'react-redux'
//import rootReducer from './reducers'
import createLogger from 'redux-logger'
import thunk from 'redux-thunk'
import {BrowserRouter} from 'react-router-dom'
import App from './containers/App'
import promise from "redux-promise-middleware"
import logger from "redux-logger"
import {fetchUsers} from "./action/UserAction"
import {fetchChart} from "./action/ChartAction"
import {fetchNames} from "./action/SearchAction"
import reducer from "./reducers"
import routes from "./routes"
const middleware = applyMiddleware(promise(), thunk, logger())
//const store= createStore(reducer,middleware)
const store= createStore(middleware)
//store.dispatch(fetchUsers());
//store.dispatch(fetchChart());
render(
<Provider store={store}>
<BrowserRouter routes={routes} />
</Provider>,
document.getElementById('root')
)
my routes.js
import App from "./pages/App"
import Users from "./pages/Users"
import Charts from "./pages/Charts"
import React from "react"
import { Route } from "react-router-dom"
export default (
<Route path="/" component={App}>
{/* <IndexRoute component={Users} /> */}
<Route path="/" component={Users}/>
<Route path="charts" name="charts" component={Charts}/>
</Route>
);
my App.js
import {Link} from "react-router"
const App = () =>(
<div>
<h1> this is main page </h1>
<Link to="charts">charts</Link>
</div>
)
export default App
my charts.js
const Chart = () => (
<h1> this is chart </h1>
)
export default Chart
my Users.js
const User = () =>(
<div>
<h1> this is user </h1>
</div>
)
export default User
and reducer is that is being called
import _intialState from "../api/names.js"
const intialValues = {names:['x','y','z','a','b','c','d','e','f'],
searchText:''}
export default function reducer(
state=intialValues,
action){
console.log("search reducer",state)
switch(action.type){
case "SEARCH":{
return Object.assign({},state,{searchText:action.payload})
}
default:
return state;
}
}
As per the react-router documentation, there is no props called routes to BrowserRouter
Instead you can specify the routes to BrowserRouter as children.
children: node
A single child element to render.
Use it like
<BrowserRouter >
{routes}
</BrowserRouter>