createBrowserhistory from history npm Url changes but not component React-redux - react-redux

Having same version for react and react-dom
"react": "^18.2.0",
"react-dom": "^18.2.0" and history is latest
"history": "^5.3.0",
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import SignInSide from "./components/mui/signIn/SignInSide";
import store from "./Store/Store";
import { Provider } from "react-redux";
import Dashboard from "./components/mui/Dashboard";
import history from './utils/history';
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<Router history={history}>
<Routes>
<Route path="/login" element={<SignInSide />} />
<Route path="/home" element={<Dashboard />} >
</Route>
<Route path="/" element={<App />} />
</Routes>
</Router>
</Provider>
</React.StrictMode>
);
function SignInSide(props) {
const handleSubmit = (event) => {
event.preventDefault();
const form = new FormData(event.currentTarget);
let user = {
email: form.get('email'),
password: form.get('password')
}
console.log(user);
props.signIn(user);
};
return (....);
Calling handleSubmit from singIn button
import { createBrowserHistory } from "history";
export function LoginUser(LogInData) {
let navigate = useNavigate;
return (dispatch) => {
dispatch(AuthActions.userSignIn());
signInWithEmailAndPassword(auth, LogInData.email, LogInData.password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
dispatch(AuthActions.userSignInSuccess(user));
setPersistence(auth, browserSessionPersistence)
.then(() => {
return signInWithEmailAndPassword(
auth,
LogInData.email,
LogInData.password
);
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
});
history.push("/home");
// console.log(store);
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
dispatch(AuthActions.userSignInFailed(error));
});
};
}
Using history.push("/home") this only Url replaced not component loading so please provide the solution with using latest npm version(if any) or suggest ready template ASAP.

The react-router-dom#6 BrowserRouter doesn't take a history prop.
BrowserRouter
declare function BrowserRouter(
props: BrowserRouterProps
): React.ReactElement;
interface BrowserRouterProps {
basename?: string;
children?: React.ReactNode;
window?: Window;
}
If you want to use a custom history object then you should import the HistoryRouter and pass the history prop for the type of history object you are creating for your app.
HistoryRouter
declare function HistoryRouter(
props: HistoryRouterProps
): React.ReactElement;
interface HistoryRouterProps {
basename?: string;
children?: React.ReactNode;
history: History;
}
Ensure that your entire app is importing and referencing the same single history object instance that is passed to the router.
Create the history object
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
Import the HistoryRouter and the custom history object.
...
import { HistoryRouter as Router, Route, Routes } from "react-router-dom";
...
import history from './utils/history';
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<Router history={history}>
<Routes>
<Route path="/login" element={<SignInSide />} />
<Route path="/home" element={<Dashboard />} >
</Route>
<Route path="/" element={<App />} />
</Routes>
</Router>
</Provider>
</React.StrictMode>
);
...
import history from './utils/history';
export function loginUser(logInData) {
return (dispatch) => {
dispatch(AuthActions.userSignIn());
signInWithEmailAndPassword(auth, logInData.email, logInData.password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
dispatch(AuthActions.userSignInSuccess(user));
setPersistence(auth, browserSessionPersistence)
.then(() => {
return signInWithEmailAndPassword(
auth,
logInData.email,
logInData.password
);
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
});
history.push("/home");
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
dispatch(AuthActions.userSignInFailed(error));
});
};
}

Related

Error: An error occured while selecting the store state: Cannot read property 'counter' of undefined

App.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
export const App = () => {
const x = useSelector(state => state.reduserDD.counter);
const dispatch = useDispatch();
console.log(x);
return (
<div>
<div onClick={() => dispatch({ type: "increment" })}>+</div>
<div onClick={() => dispatch({ type: "decrement" })}>-</div>
<div>{x}</div>
</div>
);
};
index.js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import { App } from "./App";
import { reduserDD } from "./reduser";
const store = createStore(reduserDD);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
Reducer
const initialState = {
counter: 0
};
export const reduserDD = (state = initialState, { type }) => {
switch (type) {
case "increment":
return { counter: state.counter + 1 };
case "decrement":
return { counter: state.counter - 1 };
default:
return state;
}
};
I use Redux Hook and get this error.
Error: An error occured while selecting the store state: Cannot read >property 'counter' of undefined.
What is the problem and how can I fix it?
You pass directly your reduserDD to createStore. So state.reduserDD is not existed. state is your reduserDD.
You only need to get state.counter instead of state.reduserDD.counter
const x = useSelector(state => state.counter);

redirect dependent on ajax result using react

I would like to redirect to a component in case the data of the success has a certain value.
When ajax returns the data, depending on the value of the data redirected to the Contents class that I previously imported.
I've been looking for information about the push method
My error is: Error: Invariant failed: You should not use <Redirect> outside a <Router>
import React, { Component } from 'react';
import { Modal,Button } from 'react-bootstrap';
import $ from 'jquery';
import { Redirect } from 'react-router';
import Contents from './Contents';
class Login extends Component {
constructor(props, context) {
super(props, context);
this.handleShow = this.handleShow.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleloginClick = this.handleloginClick.bind(this);
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.state = {
show: true,
username: "",
password: "",
};
}
handleloginClick(event) {
var parametros = {
username: this.state.username,
password: this.state.password
}
const { history } = this.props;
$.ajax({
data: parametros,
url: "https://privada.mgsehijos.es/react/login.php",
type: "POST",
success: function (data) {
}
});
}
handleUsernameChange(event) {
this.setState({username: event.target.value});
}
handlePasswordChange(event) {
this.setState({password: event.target.value});
}
handleClose() {
this.setState({ show: false });
}
handleShow() {
this.setState({ show: true });
}
render() {
If(Condicion){
return (<Redirect to={'./Contents'} />);
}
return (
//Here my modal.
);
}
}
export default Login;
you can use Router dom to navigate.
My fiddle: https://jsfiddle.net/leolima/fLnh9z50/1/
const AboutUs = (props) => {
console.log(props.location.state)
console.log('Hi, you are in About page, redirecting with router dom in 3 seconds')
setTimeout(() => {
props.history.push('/')}, 3000);
return <h1>Now we're here at the about us page.</h1>;
};
Full Example:
// Select the node we wish to mount our React application to
const MOUNT_NODE = document.querySelector('#app');
// Grab components out of the ReactRouterDOM that we will be using
const { BrowserRouter, Route, Switch, NavLink, Link } = window.ReactRouterDOM;
// PropTypes is used for typechecking
const PropTypes = window.PropTypes;
// Home page component
const Home = () => {
return <h1>Here we are at the home page.</h1>;
};
// AboutUs page component
const AboutUs = (props) => {
console.log(props.location.state)
return <h1>Now we're here at the about us page.</h1>;
};
// NotFoundPage component
// props.match.url contains the current url route
const NotFoundPage = ({ match }) => {
const {url} = match;
return (
<div>
<h1>Whoops!</h1>
<p><strong>{url.replace('/','')}</strong> could not be located.</p>
</div>
);
};
// Header component is our page title and navigation menu
const Header = () => {
// This is just needed to set the Home route to active
// in jsFiddle based on the URI location. Ignore.
const checkActive = (match, location) => {
if(!location) return false;
const {pathname} = location;
return pathname.indexOf('/tophergates') !== -1 || pathname.indexOf('/_display/') !== -1;
}
return (
<header>
<h1>Basic React Routing</h1>
<nav>
<ul className='navLinks'>
{/* Your home route path would generally just be '/'' */}
<li><NavLink to="/tophergates" isActive={checkActive}>Home</NavLink></li>
<li><Link to={{
pathname: "/about",
state: { fromDashboard: true }
}}>About</Link></li>
</ul>
</nav>
</header>
);
};
// Out layout component which switches content based on the route
const Layout = ({children}) => {
return (
<div>
<Header />
<main>{children}</main>
</div>
);
};
// Ensure the 'children' prop has a value (required) and the value is an element.
Layout.propTypes = {
children: PropTypes.element.isRequired,
};
// The top level component is where our routing is taking place.
// We tell the Layout component which component to render based on the current route.
const App = () => {
return (
<BrowserRouter>
<Layout>
<Switch>
<Route path='/tophergates' component={Home} />
<Route path='/_display/' component={Home} />
<Route exact path='/' component={Home} />
<Route path='/about' component={AboutUs} />
<Route path='*' component={NotFoundPage} />
</Switch>
</Layout>
</BrowserRouter>
);
};
// Render the application
ReactDOM.render(
<App />,
MOUNT_NODE
);

Can't figure out "Error: Actions must be plain objects. Use custom middleware for async actions."

I'm using React and Redux to build an app to request and subsequently display movie information from an API. In the console, I can get the requested data back but somewhere beyond that I hit the error - "Error: Actions must be plain objects. Use custom middleware for async actions."
Here's my code so far..
Search component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchMovie } from '../../actions/index';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
this.onInputChange = this.onInputChange.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onInputChange(e) {
this.setState({ term: e.target.value });
}
onFormSubmit(event) {
event.preventDefault();
this.props.fetchMovie(this.state.term);
this.setState({ term: '' });
}
render() {
return (
<div>
<form onSubmit={this.onFormSubmit} className="input-group">
<input
placeholder="Search by movie title, actor, or genre"
className="form-control"
value={this.state.term}
onChange={this.onInputChange}
/>
<span className="input-group-btn">
<button type="submit" className="btn btn-secondary">
Submit
</button>
</span>
</form>
<br />
</div>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchMovie }, dispatch);
}
export default connect(null, mapDispatchToProps)(SearchBar);
Action...
import axios from 'axios';
const API_KEY = '449a384f';
export const FETCH_MOVIE = 'FETCH_MOVIE';
let movies = [];
export function fetchMovie(term) {
const request = axios
.get(`http://www.omdbapi.com/?s=${term}&apikey=${API_KEY}`)
.then(response => {
movies = response.data;
response.json = movies;
})
.catch(error => console.log(error));
return {
type: FETCH_MOVIE,
payload: request,
};
}
Reducer...
import { FETCH_MOVIE } from '../actions/index';
export default function(state = null, action) {
switch (action.type) {
case FETCH_MOVIE:
return [action.payload.data, ...state];
}
return state;
}
CombineReducer...
import { combineReducers } from 'redux';
import MovieReducer from './movie_reducer';
const rootReducer = combineReducers({
movie: MovieReducer,
});
export default rootReducer;
Store...
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
// import ReduxThunk from 'redux-thunk';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from 'redux-promise';
import './index.css';
import App from './App';
import Login from './components/login/login';
import reducers from './reducers/reducer';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import { findDOMNode } from 'react-dom';
import $ from 'jquery';
const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<Switch>
<Route path="/Login" component={Login} />
<Route path="/" component={App} />
</Switch>
</BrowserRouter>
</Provider>,
document.querySelector('#root')
);
Thanks for the help!
Vanilla Redux requires that you return a plain JavaScript object in your action creators. Whenever, you need to perform async operations, you need to introduce middleware like redux-thunk or redux-promise to intercept the returned object an perform additional work so that a plain JavaScript object can ultimately be returned.
You're attempting to use redux-promise, but what you're returning is not causing the middleware to be invoked. Your fetchMovie() method is returning a plain object containing a Promise. In order to use redux-promise, the method needs to return a Promise.
From their documentation:
createAction('FETCH_THING', async id => {
const result = await somePromise;
return result.someValue;
});
Probably, the reason is that you're trying to return promise in the action to reducer.
You're using thunk, so you always can dispatch from action creator
export const fetchMovie = term => dispatch => axios
.get(`http://www.omdbapi.com/?s=${term}&apikey=${API_KEY}`)
.then(response => {
dispatch({
type: FETCH_MOVIE,
payload: response,
});
})
.catch(error => console.log(error));

Fetch on react / redux not work properly

I am new in react, and try to make my first project using such features: react, redux, react-router, redux-thunk. I am fetching data from url with json. It works fine on powerfull pc, on wicker it will not work becouse as i understud, it is starts to fetch then it try to render components without data and only then it gets data from url... Also same result i have when i refresh innerpage, it will try to render components before it get data.
So here is creating of store:
const middleware = [routerMiddleware(hashHistory)];
const store = createStore( combineReducers({
reducers:reducers,
routing:routerReducer
}),compose(applyMiddleware(...middleware, thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()));
const history = syncHistoryWithStore(hashHistory, store);
Then here is my provider:
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<Route path="/" component={withTransition(App)}>
<IndexRoute component={Projects} />
<Route path="project/:id/" component={SingleProject}>
</Route>
</Route>
</Router>
</ Provider>,
document.getElementsByClassName('root')[0]
)
I am fetching data in that way:
function fetchProjRequest(){
return {
type: "FETCH_PROJ_REQUEST"
}
}
function fetchProjSuccess(payload) {
return {
type: "FETCH_PROJ_SUCCESS",
payload
}
}
function fetchProjError() {
return {
type: "FETCH_PROJ_ERROR"
}
}
function fetchProj() {
const URL = "http://****.com/data/proj";
return fetch(URL, { method: 'GET'})
.then( response => Promise.all([response, response.json()]));
}
class App extends Component{
constructor(props){
super(props);
this.props.fetchProjWithRedux();
}
render(){
return (
<div className={styles.app}>
<Logo />
<TagFilter />
<div className={styles.content}>
{this.props.children}
</div>
</div>
)
}
}
function mapStateToProps(state){
return {
proj: state.proj
}
}
export default connect(
state => ({
proj: state.reducers.projects.proj
}),
dispatch =>({
fetchProjWithRedux: () => {
fetchProj().then(([response, json]) =>{
if(response.status === 200){
dispatch(fetchProjSuccess(json))
}
else{
dispatch(fetchProjError())
}
})
},
})
)(App);
It would be greate if someone of you tell me were i was wrong :( It is very imortant for me!
Here is a gist of a hoc that takes care of what you need.
Make sure to introduce a isDataLoaded boolean prop in your reducer and make it true when FETCH_PROJ_SUCCESS is called. Hope it helps.
Some changes to your code:
import dataLoader from './dataLoader';
const AppWithLoader = dataLoader(App);
export default connect(
state => ({
isDataLoaded: state.proj.isDataLoaded,
proj: state.reducers.projects.proj
}),
dispatch =>({
dispatchGetData: () => {
fetchProj().then(([response, json]) =>{
if(response.status === 200){
dispatch(fetchProjSuccess(json))
}
else{
dispatch(fetchProjError())
}
})
},
})
)(AppWithLoader);

Warning: Failed prop type: Required prop `store` was not specified in `Provider`. in Provider

I am a beginner in using react-redux, after I add <Provider> to my code,
var React = require("react");
var ReactDOM = require("react-dom");
import { Router, Route, IndexRoute, browserHistory } from "react-router";
import { Provider } from "react-redux";
var BlogApp = require("./components/BlogApp");
var Main = require("./components/Main");
var NewPost = require("./components/NewPost");
var PostDetail = require("./components/PostDetail");
var Login = require("./components/Login");
var Signup = require("./components/Signup");
import { store } from "./store/store";
ReactDOM.render((
**<Provider store={store}>**
<Router history={browserHistory}>
<Route path="/blog" component={BlogApp}>
<IndexRoute component={Main} />
<Route path="newpost" component={NewPost} />
<Route path=":postId" component={PostDetail} />
</Route>
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />
</Router>
**</Provider>**
),
document.getElementById("root")
);
the browser console report two warnings below:
Warning: Failed prop type: Required prop store was not specified in Provider.
Warning: Failed childContext type: Required child context store was not specified in Provider. in Provider
The version info related as below:
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-redux": "^4.4.5",
"react-router": "^2.8.1",
"redux": "^3.6.0",
related files:
store.js:
import { createStore } from "redux";
import { blogReducer } from "../reducers/blogReducer";
const store = createStore(blogReducer);
export default store;
blogReducer.js:
import { combineReducers } from "redux";
const state = {
posts: [
{
id: 1,
title: "test",
date: "2016.10.17",
summary: "test"
}
]
};
function posts(state = [], action) {
// TODO: temporory code
return state;
}
/* TODO: must using export, if not the browser will report error below
bundle.js:10988 Uncaught Error: Expected the reducer to be a function.(…) */
export const blogReducer = combineReducers({
posts: posts
});
export default blogReducer;
I have no idea how to fix it, can you give me a solution? TKS
My mistake, It's because the wrong import statement:
"import { store } from "./store/store";"
It should be "import store from "./store/store";"

Resources