3

So I think this question has been asked a couple of times but not sure if it's been asked appropriately. Here's what I'm going through -- I have a route that is the following:

<Route exact path={RoutePaths.PROPOSAL_ID} component={ReviewProposalView} />

The value of RoutePaths.PROPOSAL_ID is /proposal/:id

Inside of ReviewProposalView, I have the following componentDidMount() and render() methods:

class ReviewProposalView extends Component<Props, State> {
  state = {
    redirect: false,
    redirectTo: '',
    currentProposalIdIndex: // whatever current value,
    proposalIds: this.props.location.state.proposalIds,
    proposalMap: this.props.location.state.proposalMap,
    currentProposal: null
  }

  componentDidMount () {
    const {location} = this.props

    parseValueFromKeyInQueryString({queryString: location.search, key: 't'}, {
      noValueFound: () => {
        this.setState({
          redirect: true,
          redirectTo: RoutePaths.NOT_FOUND
        })
      },
      valueFound: (type: string) => {
        const {proposalMap} = this.state
        const proposalId = // ...assume we got this from pathname

        this.setState({
          currentProposal: proposalMap[proposalId]
        })
      }
    })
  }

  _confirmMatch = (confirmedProposal: Proposal) => {
    // store data on confirmedProposal
    // get next proposalId from this.state.proposalIds list

    const nextProposal = proposalMap[nextProposalId]

    this.setState({        
      redirect: true,
      redirectTo: {
        pathname: `${RoutePaths.PROPOSAL}/${nextProposal.id}`,
        search: `?t=${nextProposal.type}`,
        state: {
          currentProposalIdIndex: nextProposalIndex,
          proposalIds,
          proposalMap
        }
      }
    })
  }

  render () {
    const {currentProposal, redirect, redirectTo} = this.state

    if (redirect) {
      return <Redirect push to={redirectTo} />
    }

    const ProposalComponent = ProposalComponentMap[currentProposal.type]

    return (
        <div>
          <h1>Review Proposals Page</h1>
          <ProposalComponent {...this.props} key={currentProposal.id} proposal={currentProposal}
                             confirmProposal={this._confirmProposal} />
        </div>
    )
  }
}

// ====================================

const ProposalComponentMap = {
 'PRODUCT': ProductProposalView
 'SERVICE': ServiceProposalView 
}

The experience that this is creating is the user goes through a list of proposals and will either Accept or Reject the proposal. There are two different kinds of proposals (ProductProposalView or ServiceProposalView) that the user can interact with within this parent ReviewProposalView. The appropriate view gets rendered depending on the type of proposal we're dealing with.

Every time an Accept or Reject confirmation is made on a proposal, I want to redirect the user to the next proposal in the queue and push a new URL in the browser history stack so that I can get Back button behavior for free.

So if we start at https://myreactapp.com/proposal/id1, my ReviewProposalView goes through the entire lifecycle hitting componentDidMount at the end with no problem. My desire is that when the user goes to https://myreactapp.com/proposal/id2 as a result of confirming a proposal and getting redirected via <Redirect />, I want the entire lifecycle of the component to repeat from the beginning and to run through the logic in componentDidMount again -- essentially promoting a characteristic of immutability with a fresh instance/start.

What I currently have does not accomplish this because the ReviewProposalView is already mounted when you hit the 2nd URL. My instincts tell me that how I've structured my components is wrong and I'm fundamentally misunderstanding something about the React Component lifecycles when they are coupled with <Route />. Any and all guidance is super appreciated.

Danchez
  • 865
  • 1
  • 8
  • 26
  • Possible Duplicate of [React doesn't reload component data on route param change or query change](https://stackoverflow.com/questions/48139281/react-doesnt-reload-component-data-on-route-param-change-or-query-change/48139367#48139367) – Shubham Khatri Oct 24 '18 at 05:06
  • @ShubhamKhatri not quite. The answer to that post does not address what I'm asking here. – Danchez Oct 24 '18 at 13:30

2 Answers2

0

Hi I am also new to React.js but I understood your problem, I have already experience the same.

Actually ComponentDidMount will call if you first time go to that route and in your case you are not changing Route but changing your query params. So ComponentDidMount will not be called.

You can try componentWillReceiveProps instead of ComponentDidMount in your case.

This will cause re render the component.You need to handle specific change of your props. this example will help you for using componentWillReceiveProps hook. https://stackoverflow.com/a/32414771/1506955

Dipal
  • 184
  • 9
  • HI @Dipal, I appreciate your answer. Unfortunately, it doesn't address my ask. Moreover, in React 16, `componentWillReceiveProps` is deprecated and considered unsafe. You would have to use the new `static getDerivedStateFromProps()` method instead but I am trying to avoid doing that with the solution I'm after. Essentially, I don't want to manage more state in my views since that increases complexity. – Danchez Oct 24 '18 at 13:26
0

Try add key to route like

<Route key={type} exact path={RoutePaths.PROPOSAL_ID} component={ReviewProposalView}/>

When type change, old Component unmount and react will mount new one. So ReviewProposalView 's lifecycles start over.

Kenzk447
  • 517
  • 2
  • 7