Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Component does not re-render after mutation in React, apollo-react,graphql #3493

Closed
kartikjain26 opened this issue Sep 13, 2019 · 11 comments
Closed

Comments

@kartikjain26
Copy link

kartikjain26 commented Sep 13, 2019

Hi guys, I have ran into the following problem while integrating graphql server with React UI using Apollo-react and its hooks.

I have 2 components, Lets say ComponentA and ComponentB. These 2 are in separate files, if that matters anyhow.

const client = new ApolloClient({ uri: '/' });

export function ComponentA () {
 
  { loading, error, data } = useQuery(QUERY1, { errorPolicy: 'all', fetchPolicy: 'network-only' }),
  // do something with data if required

  let [mutationFunc1, deleting] = useMutation(QUERY2, {
    update (store, { data: response }) {

      let cachedResponse = store.readQuery({ query: TRASH_QUERY })
    // dosomething with cachedResponse
 
//updating QUERY1's cache with new response
    try {
      store.writeQuery({
        query: QUERY1,
        data: cachedResponse
      })
    }
    catch (e) {
      console.log(e);
    }
    }
  });
            return (
              <div>
                <Button1
                  className=''
                  onClick={() => { <Component2 client={client} query={QUERY1} />}); }
                >
                  'ABCD
                </Button1>
                <Button2
                  className=''
                  onClick={() => {
                        mutationFunc1({ variables: { id: '123 } });
                      }
                    });
                  }}
                />
              </div>
            );
          }
        }
      ];

    return (
      <SomeOtherComponent />
    );
  }


export default class BaseComponent extends Component {
  constructor (props) {
    super(props);
  }

  render () {
    return(
      <ApolloProvider client={client}>
        <Container className=''>
          <Component1
            {...this.props}
          />
        </Container>
      </ApolloProvider>
    );
  };
}
export function MyComponent (props) {

  let [mutationFunc2, updating] = useMutation(QUERY3, {
    update (store, { data: response }) {
  
      let cachedResponse = store.readQuery({ query: props.query })
      //do something with cached response
     
      //write new response to cache mapped to props.query (QUERY1)
      try {
        store.writeQuery({
          query: QUERY1,
          data: cachedResponse
        })
      }
      catch (e) {
        console.log(e);
      }
    }
  });

  return (
      <Button
        onClick={() => {
          mutationFunc2({ variables: { id: props.collection.id } });
        }}
      />
  );
}

export class Component2 extends Component {
  constructor (props) {
    super(props);
  }

  render () {
    return(
      <ApolloProvider client={this.props.client}>
          <MyComponent
            {...this.props}
          />
      </ApolloProvider>
    );
  };
}

BaseComponent class is where the flow begins.

There are 3 queries, QUERY1, QUERY2 (mutation), QUERY3 (mutation)

In first code block, I fetch a list with QUERY1, then I update the list with QUERY2, then I append/delete cachedResponse of QUERY1 after mutation on . (List has to be updated after mutation) -> Works fine, List gets updated real-time as component is re-rendered with new cachedResponse.

When I click I render a new Component2, with same instance of Apollo Client passed as props.

In component 2 I trigger QUERY3 (mutation query), then as before I update the cacheResponse of Query1 (List has to be updated after QUERY3 also).

However unlike first mutation, component does not re-render even after the cache is updated for QUERY1.

Can someone give me insight or point out areas in which I may be going wrong ?

Dependencies
"@apollo/react-hooks": "^3.1.0",
"react-apollo": "^3.1.0",
"graphql": "14.4.2",

@kartikjain26 kartikjain26 changed the title Re-render list after graphql mutation in React Component does not re-render after mutation in React, apollo-react,graphql Sep 13, 2019
@dylanwulf
Copy link
Contributor

dylanwulf commented Sep 13, 2019

You shouldn't modify cachedResponse. Instead, create a new object with the data you need.
A new option called freezeResults was added to InMemoryCache which helps people to avoid this kind of error by freezing results when set to true (freezing does not occur in production, only development)

@kartikjain26
Copy link
Author

@dylanwulf By freezing do you mean cache results become immutable ? In that case how do I re-render the list that I have just deleted an item from. I am not using redux store etc.

@kartikjain26
Copy link
Author

@dylanwulf I create a new object. Transfer cachedResponse (along with new data) to the new object and write the new object in store.writeQuery. is that what you meant ?

@bwesner
Copy link

bwesner commented Sep 17, 2019

I'm seeing this issue and I'm definitely constructing a new object when doing writeQuery

@kartikjain26
Copy link
Author

@bwesner @dylanwulf I got this to work, basically I was calling mutation2 in another component altogether and updating cache there. Instead I wrote mutation2 in parent component and passed it as a function (useMutation gives a functional instance), to the child component2. Whenever child component2 calls that function (onClick events etc) mutation happens and state is re-rendered as required.

@joewestcott
Copy link

joewestcott commented Sep 18, 2019

You shouldn't modify cachedResponse.

@dylanwulf Is this a breaking change in version 3? Since updating, a lot of my code relying on being able to mutate the response from store.readQuery() has stopped working.

@dylanwulf
Copy link
Contributor

You shouldn't modify cachedResponse.

@dylanwulf Is this a breaking change in version 3? Since updating a lot of my code relying on being able to mutate the response from store.readQuery() has stopped working.

As far as I know it's not a breaking change in react-apollo v3, but I think mutating the existing data was never a recommended approach. When apollo-client v3 releases, freezeResults will default to true which will prevent the existing data from being mutated.

@kartikjain26
Copy link
Author

kartikjain26 commented Sep 18, 2019

@dylanwulf Will freezeResults be configurable ? Also can you suggest ways to re-render UI after a mutation has completed. (like removing an item from a list after Delete mutation)

@dylanwulf
Copy link
Contributor

@dylanwulf Will freezeResults be configurable ? Also can you suggest ways to re-render UI after a mutation has completed. (like removing an item from a list after Delete mutation)

@kartikjain26 I don't know if freezeResults will continue to be configurable, but my guess would be yes. For re-rendering UI, you should be able to just update the cache in useMutation's update function and the components that depend on the data should re-render automatically

@kartikjain26
Copy link
Author

@dylanwulf Thanks and yes I am doing cache update in update function.

@dylanwulf
Copy link
Contributor

dylanwulf commented Sep 18, 2019

@kartikjain26 Turns out I was wrong. The freezeResults option will no longer be configurable in v3: apollographql/apollo-client#5153

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants