facebook / relay

Relay is a JavaScript framework for building data-driven React applications.
https://relay.dev
MIT License
18.4k stars 1.82k forks source link

Flickering props during `setVariables` transition #1331

Closed alex-wilmer closed 8 years ago

alex-wilmer commented 8 years ago

I can't tell if this is expected behaviour or not. I have a component that loads values from localStorage and calls setVariables to retrigger a query. As the user continues to modify the state, setVariables is called again, but until the new query has come back, Relay returns the props from the first query not the most recent one. This causes the intialVariable state to flicker briefly. Why would Relay send different props to the component at all until setVariables has finished?

const getCartFilterVariables = files => ({
  getFiles: true,
  filters: {
    content: [{
      content: {
        field: 'files.file_id',
        value: files.map(x => x.file_id),
      },
      op: 'in',
    }],
    op: 'and',
  },
})

const enhance = compose(
  lifecycle({
    componentDidMount() {
      const { files, relay } = this.props
      if (files.length) {
        relay.setVariables(getCartFilterVariables(files))
      }
    },
  }),
  shouldUpdate((props, nextProps) => {
    if (props.files.length !== nextProps.files.length && nextProps.files.length) {
      props.relay.setVariables(getCartFilterVariables(nextProps.files))
    }

    return true
  })
)

export { CartPage }

export default Relay.createContainer(
  connect(state => state.cart)(enhance(CartPage)), {
    initialVariables: {
      first: 20,
      offset: 0,
      filters: {},
      getFiles: false,
      sort: '',
    },
    fragments: {
      viewer: () => Relay.QL`
        fragment on Root {
          summary {
            aggregations(filters: $filters) {
              project__project_id {
                buckets {
                  case_count
                  doc_count
                  file_size
                  key
                }
              }
              fs { value }
            }
          }
          files {
            hits(first: $first, offset: $offset, filters: $filters, sort: $sort) {
              ${FileTable.getFragment('hits')}
            }
          }
        }
      `,
    },
  }
)

dc legacy archive20160810115421

alex-wilmer commented 8 years ago

Ah I figured this out.. I was setting the variable in prepareParams

export const prepareViewerParams = (params, { location: { query } }) => ({
  offset: parseIntParam(query.offset, 0),
  first: parseIntParam(query.first, 20),
  filters: parseJsonParam(query.filters, null), <-- setting filters variable
  sort: query.sort || '',
})

const CartRoute = h(Route, {
  path: '/cart',
  component: CartPage,
  prepareParams: prepareViewerParams, <--updating variable
  queries: viewerQuery,
})