1

Is there any guidelines on where API should take place in a component hierarchy?

I talked with a guy stating that API/REST calls should always only be in top component, and never in any child. I often find this patterns kind of hard with state management. And I know in many cases it makes sense not too.

Is this a common understanding and recommended practice, or is it OK to have API in child components too?

2
  • 3
    if that data is only required for child component then .that's completely okay to call api from child component. Commented Feb 3, 2020 at 9:20
  • 1
    it's fine to do it in child components. however, it's a good idea to separate presentational and smart components. Commented Feb 3, 2020 at 9:22

3 Answers 3

2

As of React starts to evolve into direction of functional programming and useState, useEffect and custom hooks have been around for a while, I would suggest you write your API calls as custom hooks. This is great way of dealing with side effects and it gives you lot of power in sense of reusability. Not the least functions are way much more easier to test than classes. Here is simple demo https://codesandbox.io/s/practical-cohen-mh0ee

In essence you write separate functions in which you wrap your API calls, subsriptions or some calculation logic and then use them in your functional components. You can mix and match useEffect and useState -hooks into your custom hooks as you like. When you get hang of it and can start to effeciently write small functions this is ultimately extremely effecient way to handle complexity.

As of where you use these custom hooks there are no rules written into stone. Just stay consitent with your design and things will go smoothly. Personally I like to use custom hooks where data is actually needed, but might do some exceptions if end result is more practical or makes more sense.

for representational purposes code pasted here:

const useApiFetch = () => {
  const [json, setJson] = React.useState();

  React.useEffect(() => {
    // throttle api response for visual purposes
    setTimeout(async () => {
      const response = await fetch(
        "https://jsonplaceholder.typicode.com/todos/1"
      );
      const json = await response.json();

      setJson(json);
    }, 1000);
  }, []);

  return json;
};


const Component1 = () => {
  const json = useApiFetch();

  if (!json) return <p>loading...</p>;
  return (
    <p>
      Component 1: <i>{JSON.stringify(json)}</i>
    </p>
  );
};
const Component2 = () => {
  const json = useApiFetch();

  if (!json) return <p>loading...</p>;
  return (
    <p>
      Component 2: <i>{JSON.stringify(json)}</i>
    </p>
  );
};

export default function App() {
  return (
    <div className="App">
      <h2>Component 1</h2>
      <Component1 />
      <h2>Component 2</h2>
      <Component2 />
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. This will be the road I go. I allready have my API call's isolated in service classes, so it did not take long time to refactor to this and I can allready see the benefit as I have more isolated state management for each child component.
Great to hear! We as well migrated a large codebase from class components to functional components and hooks, it can feel tedious job at the beginning but benefits will be noticeable for sure and after some time it becomes easy to notice similarities between two.
After got used to hooks useEffect becomes extremely powerful tool to seperate update logic. I recommend do a light reading about useEffect since this will be one of tools that is most heavily used. reactjs.org/docs/hooks-effect.html You can have as many useEffect as you which and second parameter of function will work as check when to run again. Empty array I used in example tells only to run when component is mounted.
1

you can use container pattern for api request:

CommentListContainer

// CommentListContainer.js

class CommentListContainer extends React.Component {
  constructor() {
    super()
    this.state = { comments: [] }
  }

  componentDidMount() {
    $.ajax({
      url: "/my-comments.json",
      dataType: 'json',
      success: comments =>
        this.setState({comments: comments});
    })
  }

  render() {
    return <CommentList comments={this.state.comments} />
  }
}

CommentList

// CommentList.js

const CommentList = ({ comments }) => (
  <ul>
    {comments.map(comment => (
      <li>
        {comment.body}-{comment.author}
      </li>
    ))}
  </ul>
);

if you use state management like redux: redux-thunk and redux-saga then handle async actions and use container pattern.

Comments

0

One way to deal with it is redux-saga

Basically we can say that API call is the side-effect while running the normal code execution so, to deal with these sort of side-effects, we separate them from normal code and move it to relevant saga files where those are handled by generator functions without affecting normal code execution.

Specific to your statement:

I talked with a guy stating that API/REST calls should always only be in top component, and never in any childs.

I do not know what your use-case is but making API calls only in Parent component does not seem correct in terms of Seperation of Concerns and Reusability.

As you already answered in next statement:

I often find this pattern kind of hard with state management

I do not think it's a common understanding or recommended practice in React or even in any programming world. If I would do API call without using redux-saga, I would do it in a relevant child component.

3 Comments

Question is where to make API calls child or parents, not how to make API calls
I think this answer is toally valid as it answers my question that it is OK to do API call's in child components. Thanks for your input. I prefer Jimi's descroption of the same answer, but thanks alot for your input. Appreciated.
Thanks @ThomasSegato, I am happy that you considered my input.

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.