0

I'm new to react, but I advanced a little and I'm facing an issue where I don't know how to express what I want in my code:

I have a "proxy" over my routes that saves info from the url to the apollo cache

function saveUrlVarsToCache(props) {
    const LOCAL_CACHE = gql`
            query localCache {
                kind @client
                name @client
                eid @client
                issueId @client
                view @client
            }
        `

    const {match} = props
    // console.log( "Match path: ", match.path )


    return (
            <Query query={LOCAL_CACHE}>
                { /***async***/ ({data, client}) => {
                    const matchParams = {...(props.match.params), ...{view: Views.findViewByPath(match.path).name}}

                    //only override if the user types the url manually
                    if (data.name)
                        delete matchParams.name
                    console.log("Writing route params to local cache ", matchParams)
                    /***await***/ client.writeData({data: matchParams})
                    return <MainComp {...props}/>
                }}
            </Query>)
}

I call this method in every route I have

<Route exact path="/:kind"
                                         render={saveUrlVarsToCache}>

My issue is that the comp is displayed before the apollo method client.writeData have finished.

I cannot put the return comp statement in a then clause since it will return to the then method and not to saveUrlVarsToCache.

What is weired is that even using the async await syntax (commented here), I get an error :

Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
    in Query (at App.js:54)
    in Route (at App.js:88)
    in Switch (at App.js:74)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:73)

Since I need the props, I cannot call this method in the componentWillMount lifecycle method...

What to do?

p.s: I can surely rerender by calling an artificial setState({}) in the then clause of the cache saving, but this will trigger an additional render() call that I don't want

p.p.s: Maybe there's a lib for that, but I don't know what they do behind the scene so i'll avoid that for now : github.com/capaj/react-promise

dance2die
  • 35,807
  • 39
  • 131
  • 194
Zied Hamdi
  • 2,400
  • 1
  • 25
  • 40
  • Maybe there's a lib for that, but I don't know what they do behind the scene so i'll avoid that for now : https://github.com/capaj/react-promise – Zied Hamdi Nov 08 '18 at 17:23

1 Answers1

0
class MainComponent extends React.Component {
  async componentDidMount()=>{
  /*call async foo here and set state*/
  }
  render() {
    return (
      <>
        <Route exact path="/:kind" 
          render={<MainComp component_prop={this.state.something} />} 
        />
      </>
    )
  }
}

try like this

dance2die
  • 35,807
  • 39
  • 131
  • 194
victor zadorozhnyy
  • 889
  • 1
  • 12
  • 25
  • Hi, thanks for the proposal, but componentDidMount hasn't props as a props neither. As mentioned in the question: i need the props: "Since I need the props, I cannot call this method in the componentWillMount lifecycle method..." – Zied Hamdi Nov 08 '18 at 17:12
  • I'm not sure to fully understand... this.props is available in the entire class. – victor zadorozhnyy Nov 08 '18 at 17:17
  • yes since the Route calls the method with these props, they should be available in the instance, I saw a method that is deprecated, componentWillReceiveProps this one should be ideal, but since it's deprecated, I think I should search for an alternative in the docs – Zied Hamdi Nov 08 '18 at 17:19
  • As mentioned in the question: p.s: I can surely rerender by calling an artificial setState({}) in the then clause of the cache saving, but this will trigger an additional render() call that I don't want So I have a plan B solution, I just want to avoid the double render – Zied Hamdi Nov 08 '18 at 17:20
  • why not to use componentDidUpdate(prevProps){const {...} = this.props} – victor zadorozhnyy Nov 08 '18 at 17:23
  • componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render. I need it only for the initial render :-) (the next render calls will have the apollo cache updated already) https://reactjs.org/docs/react-component.html#componentdidupdate – Zied Hamdi Nov 08 '18 at 17:26
  • Actually, this is related to this question: https://stackoverflow.com/questions/53210414/how-to-recognize-if-the-route-was-initiated-through-a-history-push-or-a-manual-a – Zied Hamdi Nov 08 '18 at 17:26