lkalliance
lkalliance

Reputation: 109

Problems lifting up state in React

I'm writing a web app in React.js 18, and I've got an issue that I thought I could fix with lifting state, but it's not working.

The site functions to add polls on a topic. When I create a poll in my page, the list of polls on the page doesn't update until I do a refresh. I've tried lifting the state, but either I'm not doing it correctly or I'm having an asynchronous issue.

Here is the relevant code:

Here is in App.tsx:

function App() {
  const [newPoll, setNewPoll] = useState(0);

  return (
      <div className="App">
        <Header />
        <Routes>
          <Route path="/" element={<Home polls={samplePolls} />} />
          <Route
            path="/login"
            element={
              Auth.loggedIn() ? (
                <Navigate to="/" replace={true} />
              ) : (
                <Login setLogIn={setLoggedIn} />
              )
            }
          />
          <Route
            path="/:username/:pollname"
            element={
              <Poll
                loggedin={loggedIn}
                currUser={userInfo.username}
              />
            }
          />
          <Route path="/:username" element={<Profile />} />
          <Route
            path="/create"
            element={
              !Auth.loggedIn() ? (
                <Navigate to="/" replace={true} />
              ) : (
                <Create updateList={setNewPoll} currentList={newPoll} />
              )
            }
          />
          <Route
            path="/polls"
            element={<Directory uvotes={userInfo.votes} newPoll={newPoll} />}
          />
          <Route path="*" element={<Home polls={samplePolls} />} />
        </Routes>
      </div>
    </ApolloProvider>
  );
}

The state newPoll and setNewPoll is the lifted state. I pass setNewPoll to the <Create /> page, and I pass newPoll to the <Directory />

Within <Create />, here is the quiz creation handler:

const handleCreate = async () => {
    // handler for submission of quiz to be created

    try {
      const { data } = await addPoll({
        variables: {
          ...
        },
      });
      updateList(currentList + 1);
      navigate(data.addPoll.redirect);
    } catch (err: any) {
      ( error handling is here )
    }
  };

Within <Directory />, I have this:

export function Directory({ uvotes, newPoll }: directoryProps) {
  const { loading, data } = useQuery(QUERY_ALL_POLLS, {
    variables: { ... },
  });

  const list = data?.getPolls.polls || false;

  return (
    <section id="directory" className={pollCount.created.toString()}>
      <ul>
        {list
          ? list.map((poll: userPollProps, index: number) => {
              return <PollListing key={index} index={index} poll={poll} />;
            })
          : ""}
      </ul>
    </section>
  );
}

So what I thought I was doing, was creating the state at the App level, handing the setting function to the creation function, handing the state value to the directory function, and on creation of the new poll I set the state to an essentially arbitrary value. What I expect is that immediately after creating the new poll, that if I go to the directory the new poll will be there...and it is not.

I also tried using Recoil.js, subscribing both pages to the atom, and arbitrarily changing the atom on creation...and that also didn't work.

Is there something I'm missing? Or is there a different and more relevant technique I should be using?

Upvotes: 0

Views: 61

Answers (1)

lkalliance
lkalliance

Reputation: 109

It looks like the issue wasn't with react-router, or with state lifting, but with caching. I was able to find documentation for refetching queries in Apollo Server, and this worked well. One can define specific queries to be re-run following specific mutations in specific React components. Here I've done so with the ADD_POLL mutation in the create component:

const [addPoll] = useMutation(ADD_POLL, {
    refetchQueries: [QUERY_ALL_POLLS],
  });

Upvotes: 1

Related Questions