最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to redirect from an action event in redux - Stack Overflow

programmeradmin4浏览0评论

I want to redirect the client after an action has been fired. I heard of react-redux-router, but not sure how to properly implement it in the actions function.

i followed a little bit of this

However, when i submit the validated form, it doesn't redirect or refreshes.

Actions.js

 import { auth as firebaseAuth } from '../firebaseConfig'
 import { push,  browserHistory } from 'react-router-redux';


 export const signUp = (user) => { return (dispatch) => {
  firebaseAuth.createUserWithEmailAndPassword(user.email, user.password)
    .then(() => {
        dispatch({ type: 'SIGNUP_SUCCESS',
        payload: (action, state, res) => {
            return res.json().then(json => {
              browserHistory.push('/');
              return json;
            });
          },
    });
    }).catch((err) => {
        dispatch({ type: 'SIGNUP_ERROR', err});
    });
  }  
}

Reducers.js

const initialState = {
  emailSignUp: '',
  passwordSignUp: '',
  authError: null

}

export default (state = initialState, action) => {
  switch (action.type) {
    case 'SIGNUP_SUCCESS':      
        return ({
            ...state,
            authError: null
        })

    case 'SIGNUP_ERROR':
        console.log('signup error')
        return ({
            ...state,
            authError: action.err.message
        })
    default:
        return state
 }
} 

Register.js

// ...
handleSubmit(event) {
    event.preventDefault();

    const {formData, errors} = this.state;
    const {email, password} = formData;

    const myError = this.props.authError;
    const creds = {
        email,
        password
    }
    const register = this.props.signUp(creds);
    if (register) {
        console.log(creds);

    }
}

I want to redirect the client after an action has been fired. I heard of react-redux-router, but not sure how to properly implement it in the actions function.

i followed a little bit of this

https://stackoverflow./a/42985875/10865515

However, when i submit the validated form, it doesn't redirect or refreshes.

Actions.js

 import { auth as firebaseAuth } from '../firebaseConfig'
 import { push,  browserHistory } from 'react-router-redux';


 export const signUp = (user) => { return (dispatch) => {
  firebaseAuth.createUserWithEmailAndPassword(user.email, user.password)
    .then(() => {
        dispatch({ type: 'SIGNUP_SUCCESS',
        payload: (action, state, res) => {
            return res.json().then(json => {
              browserHistory.push('/');
              return json;
            });
          },
    });
    }).catch((err) => {
        dispatch({ type: 'SIGNUP_ERROR', err});
    });
  }  
}

Reducers.js

const initialState = {
  emailSignUp: '',
  passwordSignUp: '',
  authError: null

}

export default (state = initialState, action) => {
  switch (action.type) {
    case 'SIGNUP_SUCCESS':      
        return ({
            ...state,
            authError: null
        })

    case 'SIGNUP_ERROR':
        console.log('signup error')
        return ({
            ...state,
            authError: action.err.message
        })
    default:
        return state
 }
} 

Register.js

// ...
handleSubmit(event) {
    event.preventDefault();

    const {formData, errors} = this.state;
    const {email, password} = formData;

    const myError = this.props.authError;
    const creds = {
        email,
        password
    }
    const register = this.props.signUp(creds);
    if (register) {
        console.log(creds);

    }
}
Share Improve this question asked Jan 4, 2019 at 9:54 Eric ThomasEric Thomas 211 gold badge2 silver badges6 bronze badges 1
  • Maybe this post will help stackoverflow./questions/48514773/… – Shubham Khatri Commented Jan 4, 2019 at 10:39
Add a ment  | 

3 Answers 3

Reset to default 6

You should implement the react-router-dom library which gives you access to the history object for navigation.

In your ponent that is firing the action creator:

import { withRouter } from "react-router-dom"

Then at the bottom of the code, where you call connect:

export default connect(mapStateToProps, mapDispatchToProps)(withRouter(myComponent))

Now you can set up your action creator to take in history as an argument.

Your actions file:

const signUp = (creds, history) => {
//do some logic then go home
   history.push("/")
}

So in your event handler where you call your action creator, pass in history:

handleSubmit(event) {
    event.preventDefault();

    this.props.signUp(creds, this.props.history);
    if (register) {
        console.log(creds);
    }
}

This is my example with firebase and redux:

Inside your actions you create the user and dispatch appropriate actions to your reducer:

export const signUp = newUser => {
  return (dispatch, getState, { getFirebase, getFirestore }) => {
    const firebase = getFirebase();
    const firestore = getFirestore();

    firebase
      .auth()
      .createUserWithEmailAndPassword(newUser.email, newUser.password)
      .then(resp => {
        return firestore
          .collection('users')
          .doc(resp.user.uid)
          .set({
            firstName: newUser.firstName,
            lastName: newUser.lastName
          });
      })
      .then(() => {
        dispatch({ type: 'SIGNUP_SUCCESS' });
      })
      .catch(err => {
        dispatch({ type: 'SIGNUP_ERROR', err });
      });
  };
};

In your reducer you handle the state change:

    case 'SIGNUP_SUCCESS':
        return {
            ...state,
            authError: null
        };
    case 'SIGNUP_ERROR':
        return {
            ...state,
            authError: action.err.message
        };

In the ponent you import Redirect from react-router-dom and redirect on successful signup:

    import { Redirect } from 'react-router-dom';

    class SignIn extends Component {
        state = {
            email: '',
            password: ''
        };
        handleChange = e => {
            this.setState({
                [e.target.id]: e.target.value
            });
        };
        handleSubmit = e => {
            e.preventDefault();
            this.props.signIn(this.state);
        };
        render() {
            const { authError, auth } = this.props;
            if (auth.uid) return <Redirect to="/" />;
            return (
                <div className="container">
                    <form onSubmit={this.handleSubmit} className="white">
                     ...
                    </form>
                </div>
            );
        }
    }

    const mapStateToProps = state => {
        return {
            authError: state.auth.authError,
            auth: state.firebase.auth
        };
    };

    const mapDispatchToProps = dispatch => {
        return {
            signIn: creds => dispatch(signIn(creds))
        };
    };

    export default connect(
        mapStateToProps,
        mapDispatchToProps
    )(SignIn);

I fixed it.

Apart of the problem stemmed from this

React history.push() is updating url but not navigating to it in browser

and not knowing how to properly use then

I needed to wrap the router tags around the app

import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware, pose } from 'redux'
import { Provider } from 'react-redux';
import rootReducer from './reducers';
import thunk from 'redux-thunk'
import { BrowserRouter as Router } from 'react-router-dom';
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);

ReactDOM.render(
    <Provider store={createStoreWithMiddleware(rootReducer)}>
     <Router >
      <App />
      </Router>
    </Provider>

    ,document.getElementById('root'));

and update my actions like so

import { push } from 'react-router-redux';
import { history } from '../ponents/Navbar';

export const signUp = (user) => { return (dispatch) => {
    firebaseAuth.createUserWithEmailAndPassword(user.email, user.password)
        .then(() => {
            dispatch({ type: 'SIGNUP_SUCCESS' })
        }).then((response) => {
            history.push('/');
        }).catch((err) => {
            dispatch({ type: 'SIGNUP_ERROR', err});
        });


    }

}

Navbar.js

import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import createBrowserHistory from 'history/createBrowserHistory';
import SignUp from './SignUp';
import SignIn from './SignIn';
// forcerefresh does the magic.
export const history = createBrowserHistory({forceRefresh:true});

const Navbar = () => {
    return(

    <Router history={history}>
        <div>
        <nav className="navbar navbar-expand-lg navbar-light bg-light ">
          <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExample08" aria-controls="navbarsExample08" aria-expanded="false" aria-label="Toggle navigation">
            <span className="navbar-toggler-icon"></span>
          </button>

          <div className="collapse navbar-collapse justify-content-md-center" id="navbarsExample08">
            <ul className="navbar-nav">

                <li className="nav-item">
                    <Link className="nav-link" to="/">Home </Link>
                </li>
                <li className="nav-item">
                    <Link className="nav-link" to="/SignUp">Sign Up </Link>
                </li>
                <li className="nav-item">
                    <Link  className="nav-link" to="/SignIn">Sign In </Link>
                </li>


            </ul>
          </div>
        </nav>
        <Route path="/SignUp" ponent={SignUp} />
        <Route path="/SignIn" ponent={SignIn} />
        <Route path="/"/>


    </div>
    </Router>
    );

}

export default Navbar;

Keep my existing handleSubmit function the same.

发布评论

评论列表(0)

  1. 暂无评论