Saturday, October 7, 2017

componentDidMount not running after calling browserHistory.push(“/url”)

Leave a Comment

I have an issue where I will send a user to a react-router route after login, based on the following:

        ...         //check login         browserHistory.push(self.props.destination_url); 

I was expecting componentDidMount to run, since this component had not been on the screen since I loaded the app, but it will not. If I click a link to it (react-router link) in the nav bar, componentDidMount does run however.

I just need to make an API call when this component comes on the screen because of a browserHistory.push(self.props.destination_url); route change. I've tried things like

<Router createElement={ (component, props) => {   const { location } = props   const key = `${location.pathname}${location.search}`   props = { ...props, key }   return React.createElement(component, props) } }/> 

here Component does not remount when route parameters change and it isn't working.

Here http://busypeoples.github.io/post/react-component-lifecycle/ shows "on mount", "on unmount", "on state change", or "on props changes". I'm not seeing any of those apply here. Is there a lifecycle method that will run after this browserHistory push transition? Thank you

I've been trying random lifecycle methods and componentWillUpdate does run after browserHistory.push but it runs hundreds of times, completely slowing the app down. I'd assume something I did inside it caused the nearly infinite loop:

componentWillUpdate() {     console.log('it ran componentWillUpdate');     if (this.props.email) {          console.log('firing off /api/userInfo');         let self = this;         axios.post('/api/userInfo', {email: this.props.email})           .then(function (response) {               let result = response.data.result;               console.log('after calling /api/userInfo');               console.log(response);               console.log(result);               if (result) {                   self.setState({restaurant_profile: result});               }           })           .catch(function (error) {               console.log("Something went wrong trying to check for a user's restaurant profile");               console.log(error);           });     } } 

On the server/client you now see the POST run hundreds of times:

Executing (default): SELECT `id`, `email`, `password`, `RestaurantId` FROM `Users` AS `User` WHERE `User`.`email` = 'fake@fake.com' LIMIT 1;  Executing (default): SELECT `id`, `email`, `password`, `RestaurantId` FROM `Users` AS `User` WHERE `User`.`email` = 'fake@fake.com' LIMIT 1;  Executing (default): SELECT `id`, `email`, `password`, `RestaurantId` FROM `Users` AS `User` WHERE `User`.`email` = 'fake@fake.com' LIMIT 1;  Executing (default): SELECT `id`, `email`, `password`, `RestaurantId` FROM `Users` AS `User` WHERE `User`.`email` = 'fake@fake.com' LIMIT 1;  ... 

This will work for the student's demo, but not longterm. Looking for a lifecycle method that will only run once, and that changing state is safe and won't cause infinite loop

My r dependencies look like

"react": "^15.6.1", "react-dom": "^15.6.1", "react-redux": "^5.0.6", "react-router": "^3.0.5", "react-router-dom": "^4.2.2", "react-transform-hmr": "^1.0.4", "redux": "^3.7.2", 

These routes are looking like

import React from "react"; import ReactDOM from "react-dom"; import { Provider } from "react-redux"; import { createStore, applyMiddleware } from "redux"; import { Router, Route, Link, IndexRoute, browserHistory } from "react-router";  import reducers from "./reducers"; import { loadConfig, getConfig } from "./config"; import Nav from "./Nav"; import LoginPage from "./containers/LoginPage"; import MapShowRestaurants from "./components/MapShowRestaurants"; import RestaurantRegistration from "./containers/RestaurantRegistration";   const createStoreWithMiddleware = applyMiddleware()(createStore);   getConfig.then((config) => {     loadConfig(config);      ReactDOM.render(         (             <Provider store={createStoreWithMiddleware(reducers)}>                 <Router history={browserHistory}>                     <Route path="/" component={Nav}>                         <IndexRoute component={MapShowRestaurants} />                         <Route path="/login" component={LoginPage} />                         <Route path="/registerRestaurant" component={RestaurantRegistration} />                     </Route>                 </Router>             </Provider>         ), document.querySelector('.container')); }) .catch((err) => {     console.log(err); }) 

Thank you

2 Answers

Answers 1

don't put API calls in a component lifecycle.

create an action

function getUserInfo(payload) {   // do axios   return {        type: 'GET_USER_INFO',       payload: result_of_your_api_call,       error: false/true   }; } 

create reducer for this action and mutate state in reducer

after that, you need to matStateToProps and mapDispatchToProps

connect(mapStateToProps, mapDispatchToProps)(YourMagicComponent) 

that connects your component and your redux

After that, you get a redux state in your component. For more information please read this http://redux.js.org/docs/basics/ExampleTodoList.html

Remember 1. when component initialized it hasn't any data in props except defaultProps. 2. componentDidMount doesn't know anything outside component (available only default props and props defined before component mounted) 3. if you need to do something in componentWillUpdate you need to define rules for update that's component

componentWillUpdate(nextProps) {   this.setState(key: nextProps.key) }  shouldComponentUpdate(nextProps, nextState) {   // fix for your update   if (this.state.key !== nextProps.key) {      return true;   } } 

Answers 2

@codyc4321 try self.props.router.push('/url')

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment