skip to Main Content

Is this an anti-pattern in React if I do this? How can I improve?

I have an EventItem Component and another helper file – EventHelper.js which handles all the axios calls for the said component. The functions declared in this helper file receives states and setStates from the EventItem component. The functions in this helper file make the HTTP calls and sets the state in EventItem component. Something like this:

EventItem.js (Component):

import {getPostComments} from "../Services/EventHelpers";

function EventItem(props) {
  const [eventComments, setEventComments] = useState([]);
  const [loadingComments, setLoadingComments] = useState(false);

  const getPostCommentsHandler = async (eventId) => {
    await getPostComments(
      eventId,
      setLoadingComments,
      eventComments,
      setEventComments
    );
  };
}

EventHelper.js:

export const getPostComments = async (
  eventId,
  setLoadingComments,
  eventComments,
  setEventComments
) => {
  try {
    setLoadingComments(true);
    const res = await axios.get(`/events/${eventId}/comments`);
    setLoadingComments(false);
    setEventComments(...[...eventComments, res.data.comments]);
  } catch (e) {}
};

2

Answers


  1. You can do the following

    // api.js
    
    import axios from 'axios'
    
    const api = {
      comments: async (eventId) => {
        const res = await axios.get(`/events/${eventId}/comments`);
        return res
      }
    }
    export default api
    

    Whereby

    // EventItem.js
    import {getPostComments} from "../Services/EventHelpers";
    
    function EventItem(props) {
      const [eventComments, setEventComments] = useState([]);
      const [loadingComments, setLoadingComments] = useState(false);
    
      const getPostCommentsHandler = async (eventId) => {
        await getPostComments(
          eventId,
          setLoadingComments,
          eventComments,
          setEventComments
        );
      };
    }
    

    Such that the EventHelper.js is thus:

    // EventHelper.js
    import api from './api'
    
    export const getPostComments = async (
      eventId,
      setLoadingComments,
      eventComments,
      setEventComments
    ) => {
      try {
        setLoadingComments(true);
        const comments = await api.comments(eventId)
        setLoadingComments(false);
        setEventComments(...[...eventComments, comments]);
      } catch (e) {}
    };
    

    Explaination:

    For the api.js – you may want to abstract the api to be used in various components/hooks. the idea is that when anyone can use the api (where there is a common interface).

    Login or Signup to reply.
  2. Your way of writing this code is a valid way. For these kind of states and functions React recommends creating custom hooks.

    The following code allows you to move all your state needed for getting the post comments to a separate hook. This will result in a cleaner component and you can reuse this hook in a different component.

    export function usePostComments() {
      const [eventComments, setEventComments] = useState([]);
      const [isLoading, setIsLoading] = useState(false);
    
      const getPostComments = async (eventId) => {
        try {
          setIsLoading(true);
          const res = await axios.get(`/events/${eventId}/comments`);
    
          setEventComments((prevComments) => {
            return [...prevComments, res.data.comments];
            // or this below, not sure if you're comments data is a array
            // return [...prevComments, ...res.data.comments];
          });
        } catch (e) {
          console.error(e);
        } finally {
          setIsLoading(false);
        }
      };
    
      return {
        isLoading,
        eventComments,
        getPostComments,
      };
    }
    

    In the EventItem you could use it something like this, obviously very abstract but you’ll get the idea.

    import { usePostComments } from "../hooks";
    
    function EventItem(props) {
      const { isLoading, eventComments, getPostComments } = usePostComments();
    
      return (
        <div>
          <button onClick={() => getPostComments("some-id")}>Get posts</button>
          {isLoading ? (
            <p>Sorry still loading</p>
          ) : (
            <div>
              {eventComments.map((comment) => {
                <p>{comment.stuff}</p>;
              })}
            </div>
          )}
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search