How to setState() in React/Apollo with graphQL
Asked Answered
M

3

6

I am trying to setState() to a query result I have from graphQL, but I am having difficulty finding out how to do this because it will always be loading, or it's only used from props. I first set the state

constructor (props) {
        super(props);
        this.state = { data: [] };

Then I have this query

const AllParams = gql`
    query AllParamsQuery {
        params {
            id,
            param,
            input
        }
    }`

And when it comes back I can access it with this.props.AllParamsQuery.params

How and when should I this.setState({ data: this.props.AllParamsQuery.params }) without it returning {data: undefined}?

I haven't found a way to make it wait while it's undefined AKA loading: true then setState. I've tried componentDidMount() and componentWillReceiveProps() including a async function(){...await...} but was unsuccessful, I am likely doing it wrong. Any one know how to do this correctly or have an example?

EDIT + Answer: you should not setstate and just leave it in props. Check out this link: "Why setting props as state in react.js is blasphemy" http://johnnyji.me/react/2015/06/26/why-setting-props-as-state-in-react-is-blasphemy.html There is more to the problem to update props, but some great examples can be found at this app creation tutorial: https://www.howtographql.com/react-apollo/8-subscriptions/

Multiple answered 27/9, 2017 at 20:52 Comment(1)
Broken link. Here's a wayback machine snapshot web.archive.org/web/20200125010920/http://johnnyji.me/react/…Papuan
L
5

A simple solution is to separate your Apollo query components and React stateful components. Coming from Redux, it's not unusual to transform incoming props for local component state using mapStateToProps and componentWillReceiveProps. However, this pattern gets messy with Apollo's <Query />.

So simply create a separate component which fetches data:

...

export class WidgetsContainer extends Component {
  render (
    <Query query={GET_WIDGETS}>
      {({ loading, error, data }) => {
        if (loading) return <Loader active inline="centered" />;

        const { widgets } = data;
        return (
          <Widgets widgets={widgets} />
        )
      }}
    </Query>
  )
}

And now the Widgets components can now use setState as normal:

...
export class Widgets extends Component {
  ...
  constructor(props) {
    super()

    const { widgets } = props;
    this.state = {
      filteredWidgets: widgets
    };
  }

  filterWidget = e => {
    // some filtering logic
    this.setState({ filteredWidgets });
  }

  render() {
    const { filteredWidgets } = this.state;
    return (
      <div>
        <input type="text" onChange={this.filterWidgets} />
        {filteredWidgets.count}
      </div>
    )
  }
}
Landeros answered 5/3, 2019 at 2:57 Comment(0)
S
1

What is the reason behind setting it to state? Keep in mind, Apollo Client uses an internal redux store to manage queries. If you're trying to trigger a re render based on when something changes in the query, you should be using refetchQueries(). If you absolutely need to store it in local state, I would assume you could probably compare nextProps in componentWillReceiveProps to detect when loading (the value that comes back when you execute a query from apollo client) has changed, then update your state.

Seller answered 28/9, 2017 at 3:3 Comment(3)
Agreed, I found out that it doesn't make sense to use state, and to leave it in props!Multiple
this is the reason: Here is the "Why setting props as state in react.js is blasphemy" johnnyji.me/react/2015/06/26/…Multiple
Cool, Apollo is makes things super easy!Seller
N
1

I had a similar issue (although it was happening for a totally different reason). My state kept getting set to undefined. I was able to solve it with a React middleware. It made it easy to avoid this issue. I ended up using superagent.

http://www.sohamkamani.com/blog/2016/06/05/redux-apis/

Nimble answered 28/9, 2017 at 3:16 Comment(2)
thanks Eric, I believe it was actually bad to use setstate. See: Here is the "Why setting props as state in react.js is blasphemy" johnnyji.me/react/2015/06/26/…Multiple
Ahh. Yeah, if you just need immutable data, than forget setting props as state.Nimble

© 2022 - 2024 — McMap. All rights reserved.