3

I'm new to React and using Zustand to handle global stores. My goal in this particular instance is to route to an "RSVP" page if the correct user is found.

Scenario A: User is found in the database. Route to new page

Scenario B: User is not found in the database. Stay on current page and display error message

It seems straightforward if you want to achieve this on click, however I can't find any information on how to trigger it within a state.

My understanding is that useHistory can be used, but only within a function, so it doesn't work when I try to use it in a state. eg.

import create from 'zustand';
import { mountStoreDevtool } from 'simple-zustand-devtools';
import { useHistory } from "react-router-dom";


const useStore = create((set, get) => ({
  guests: [],
  currentGuests: [],
  message: "Please enter your unique password found in your email.",
  returnDatabase: (input) => {
    const guests = get().guests;

    const targetParty = guests.filter((guest) => guest.party === input);
    
    if (targetParty.length !== 0) {
      set({ currentGuests: targetParty });
      const setMessage = "Please enter your unique password found in your email.";
      set({ message: setMessage });

      //I want to programatically redirect here
      let history = useHistory();
      history.push("/rsvp");

    } else {
      const setMessage = "Your password has not been found. Please check your email and try again.";
      set({ message: setMessage });
    }
  
  },
  setStore: (data) => {
    const guestsData = data.guests;
    set({ guests: guestsData });
  },
}));

However, I'm receiving this error:

Failed to compile
src/store/storeUtil.js
  Line 19:21:  React Hook "useHistory" is called in function "returnDatabase" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter  react-hooks/rules-of-hooks

Search for the keywords to learn more about each error.

I figure this is because it's not in a function, so I tried to put it in a separate component:

import create from 'zustand';
import { mountStoreDevtool } from 'simple-zustand-devtools';
import { useHistory } from "react-router-dom";

  export function RsvpButton(){
    let history = useHistory();
  
    function handleClick() {
      history.push("/rsvp");
    }
  
    return (
      {handleClick}
    );
  }


const useStore = create((set, get) => ({
  guests: [],
  currentGuests: [],
  message: "Please enter your unique password found in your email.",
  returnDatabase: (input) => {
    const guests = get().guests;

    const targetParty = guests.filter((guest) => guest.party === input);
    
    if (targetParty.length !== 0) {
      set({ currentGuests: targetParty });
      const setMessage = "Please enter your unique password found in your email.";
      set({ message: setMessage });

      //try to use component here 
      <RsvpButton />

...etc

And this just doesn't do anything/have any errors. Should I be using a different method to route to the RSVP page other than useHistory? Or am I doing something wrong in my implementation?

2 Answers 2

1

Your button component RsvpButton is not creating a button.

The code for function RsvpButton should be something like

export function RsvpButton () {
    ... 
    return (
        <button onClick={handleClick}>Rsvp</button>
    ) 
}

That way, the handleClick function will be linked to the onClick property of the button, which will make it run upon clicking the button.

Sign up to request clarification or add additional context in comments.

1 Comment

Hi Rituraj, thanks for the answer. My problem is, I want it to trigger manually (i.e. not on click) depending on the logic. If user is on the list: Trigger route If user is not on the list: Stay on same page and display error message I'll edit the question for more clarity.
0

Solution for anyone having a similar issue:

To solve this, I put the useHistory handler in the parent component RsvpContainer.js

import { useHistory } from 'react-router-dom';
    useEffect(() => {
      loadData();
    });
    return (
        <React.Fragment>
            <div className="header">
                <div className="Bg section-2"></div>
                <div className="divider"></div>
                <div className="App section-2">
                    <h3>RSVP.</h3>
                    <h2>Saturday 30 October, 2021</h2>
                    <Input 
                        filter={filter} 
                        setFilter={setFilter}
                        returnDatabaseHandler={returnDatabaseHandler}
                        onUserFound={onUserFoundHandler}
                    />
                        
                </div>
            </div>
        </React.Fragment>
    )

Input.js

export function Input({ setFilter, filter, onUserFound }) {
  const isUserFound = useStore((state) => state.isUserFound);

  useEffect(() => {
    if (isUserFound) {
      onUserFound();
    }
  }, [isUserFound]);

}

storeUtil.js (zustand global store) - I added this in 'returnDatabase'

  set({
    message: setMessage,
    isUserFound: true
  });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.