12

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?

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);
})
halfer
  • 19,824
  • 17
  • 99
  • 186
codyc4321
  • 9,014
  • 22
  • 92
  • 165
  • I know that componentDidMount only gets called once which is why it's not working as you expect (because (i believe) react-router does an initial render before it's actually called) I could be wrong - hence the comment and not an answer. I'll see if i can't find the docs for that. Also, as you've discovered, componentWillUpdate() isn't the right place for that either... you might try creating your own method and then call it in the browserPush callback? Just a thought. – rimraf Oct 01 '17 at 01:31
  • how would I call it in `browserHistory.push`? From what I understand you just pass it the URL you want to go to and it pushes it into the history and reroutes you there – codyc4321 Oct 01 '17 at 01:51
  • I thought you could add a callback... when looking for that info i found this: https://github.com/ReactTraining/react-router/issues/3554 – rimraf Oct 01 '17 at 02:21
  • see jayzee's comment on june 1st about the event listener... you'd add that on componentWillMount and then call the unListen on componentWillUnmount. – rimraf Oct 01 '17 at 02:23
  • 1
    @codyc4321 can you provide us two things? First and important, which version of react router are you using, and second, your defined routes. Thanks – rdarioduarte Oct 02 '17 at 01:22
  • If the component it's drawn at all it must go through either componentDidMount or componentDidUpdate. I would check this out. – xabitrigo Oct 02 '17 at 22:40
  • Yes Dario, it's added ty – codyc4321 Oct 03 '17 at 13:30
  • Yes xabritigo both did work, I realize now it might be only componentWillUpdate causing the infinite loop. I'll try that one – codyc4321 Oct 03 '17 at 13:31
  • 1
    @codyc4321 are you sure that "componentDidMount" is not getting called? I tried to replicate your scenario as best as I could in this sandbox: https://codesandbox.io/s/ov84yrzyy5 it works as I would expect it to, `componentDidMount` is getting called every time I "navigate" to that component, it does not get called when I am already ON that component. – dubes Oct 06 '17 at 13:13
  • It wasn't getting called if I had visited the component, went to a different one, then got back to it by the `.push()` method – codyc4321 Oct 09 '17 at 03:22

2 Answers2

5

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;
  }
}
Daniel Rosenberg
  • 600
  • 6
  • 11
2

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

dhruv soni
  • 89
  • 6
  • Can you please add some context to your answer? Why should this work? What is the mistake it is fixing when compared to what the OP has tried. – dubes Oct 06 '17 at 13:14
  • I've got a test for a job, I'll reopen bounty when I can verify these – codyc4321 Oct 06 '17 at 13:38