-1

I have some code in a MERN stack app where users can enter another user's name into a search bar, and the webpage will return other properties of the user whose name they searched up.

For example, if I search up "John Doe" in the search bar, it should return something like this in the front end:

Name: John Doe
Age: 30
Sex: Male

Here is the code for the React component I made to handle this:

import React, { useState, useEffect } from "react";
import axios from "axios";
import "../../styles/styles.css";

function SearchUser() {
  const [user, setUser] = useState({});
  const [searchQuery, setSearchQuery] = useState("");
  const [formError, setFormError] = useState(false);

  async function getUsers(query) {
    const response = await axios.get(`http://localhost:5000/auth/userSearch?fullName=${query}`);
    setUser(response.data);
  }

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!searchQuery) {
      setFormError(true);
      return;
    }

    setFormError(false);
    getUsers(searchQuery);
  };

  useEffect(() => {
    console.log(user);
  }, [user]);

  return (
    <div className="container">
      <div className="create-profile-border">
        <h1>Search a user</h1>
        <form onSubmit={handleSubmit}>
          <div>
            <input
              type="text"
              placeholder="Enter a user's full name here"
              onChange={(e) => {
                setSearchQuery(e.target.value);
              }}
              value={searchQuery}
            />
            {formError && !searchQuery && (
              <p className="error-message">This is a required field</p>
            )}
          </div>
          <button className="create-profile-button" type="submit">
            Search
          </button>
        </form>

        {user.fullName > 0 && (
          <div>
            <p>Name: {user.fullName}</p>
            <p>Age: {user.age}</p>
            <p>Sex: {user.sex}</p>
          </div>
        )}
      </div>
    </div>
  );
}


export default SearchUser;

I have checked and confirmed that the backend code is working properly, the issue purely lies in the frontend.

The Issue I have:

After debugging and some console logging, it seems that user.fullName/user.age/user.email are all undefined. However, in this console log:

useEffect(() => {
    console.log("effect[user]:", JSON.stringify(user));
  }, [user]);

I get back a user object in the browser console when I type "John Doe" in the search bar:

effect[user]: {"user":{"_id":"63eea67c0316be96ebf799f0","email":"johndoe@example.com","passwordHash":"DU7fwnIlucrwT7R","fullName":"John Doe","age":"30","sex":"male","__v":0}}

I suspect there's some funny business with the rendering but as I'm still inexperienced with React, I'm not sure where to go from here. Any help would be greatly appreciated.

3 Answers3

1

I subscribe to all the suggestions from phil. However, after looking at the log from your console, I think your data is returned as a user. so you should be able to get the data by setting user to response.data.user

async function getUsers(query) {
    const response = await axios.get(`http://localhost:5000/auth/userSearch?fullName=${query}`);
    setUser(response.data.user);
  }

or

const getUsers = async (fullName) => {
  setUser(
    (
      await axios.get("/auth/userSearch", {
        baseURL: "http://localhost:5000/", // even better, use your .env file
        params: { fullName },
      })
    ).data.user
  );
};
franklin
  • 89
  • 4
0

Your main issue is trying to compare the string property user.fullName to numeric 0. Unless your string is purely numeric, user.fullName > 0 will always be false.

Instead of initialising user to be an empty object, try starting it with null. Then you can more easily test if it has a value or not...

const [user, setUser] = useState(null);

// ...

{user && (
  <div>
    <p>Name: {user.fullName}</p>
    <p>Age: {user.age}</p>
    <p>Sex: {user.sex}</p>
  </div>
)}

Another improvement you can make is to employ Axios' params option to correctly encode URL query parameters.

Update: after prompting you to debug your own API response, it also seems your response data is nested under a user property

const getUsers = async (fullName) => {
  setUser(
    (
      await axios.get("/auth/userSearch", {
        baseURL: "http://localhost:5000/", // even better, use your .env file
        params: { fullName },
      })
    ).data.user //  extract the `user` property
  );
};

Edit compassionate-gwen-ztvy8x

Phil
  • 157,677
  • 23
  • 242
  • 245
  • Thanks for your axios tips. I set `const [user, setUser] = useState(null)` and changed `user.fullName > 0` to just `user`. Issue still persist however. When I `console.log(user)` in `handleSubmit`, I get back `null`. However, when I `console.log(user)` under `useEffect()` I get the proper user object returned. Know what's causing that? – God's Drunkest Driver Feb 20 '23 at 01:43
  • Why are you logging your state values? There's no need to and [the results are often confusing](https://stackoverflow.com/q/54069253/283366) for developers new to React. I'd suggest using better debugging tools like the [React Dev Tools](https://beta.reactjs.org/learn/react-developer-tools) browser extension and that's only if you actually need to do any debugging – Phil Feb 20 '23 at 01:46
  • I'm getting still `null` values for `user`. What's the error in my logic? Bear in mind I've tested out my backend a ton so I know for a fact that the issue isn't with the router. When the submit button is clicked, `handleSubmit` is ran that runs `getUsers`, which in turn sets the `user` object based on the search query. If my backend is returning the correct `user` when a search is queried, what did I do wrong in my front-end code? – God's Drunkest Driver Feb 20 '23 at 05:54
  • Can you change your effect hook logger to use `console.log("effect[user]:", JSON.stringify(user))` like in my CodeSandbox link? Then [edit](https://stackoverflow.com/posts/75488997/edit) your question with the details – Phil Feb 20 '23 at 06:10
  • Edited my post accordingly – God's Drunkest Driver Feb 20 '23 at 18:14
  • @God'sDrunkestDriver so the original data you presented wasn't actually what your data looks like? Aren't you in control of the API response? Shouldn't you have known the data structure? – Phil Feb 20 '23 at 22:10
0

Can you share the full JSON response from your API? I'm asking because what you pasted seems to imply the response looks something like this:

{
  user: { _id: "...", email: "...", passwordHash: "..." },
  _id: "63eea67c0316be96ebf799f0"
  fullName: "John Doe"
​​  age: "30"
}

Said another way... Based on your paste, the data.user object does not contain the fullName property, but rather data.fullName does.

tdc
  • 5,174
  • 12
  • 53
  • 102