React – What’s concurrent mode (1)?

Suspense

fetch-on-render

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

  useEffect(() => {
    fetchUser().then(u => setUser(u));
  }, []);

  if (user === null) {
    return <p>Loading profile...</p>;
  }
  return (
    <>
      <h1>{user.name}</h1>
      <ProfileTimeline />
    </>
  );
}

function ProfileTimeline() {
  const [posts, setPosts] = useState(null);

  useEffect(() => {
    fetchPosts().then(p => setPosts(p));
  }, []);

  if (posts === null) {
    return <h2>Loading posts...</h2>;
  }
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.text}</li>
      ))}
    </ul>
  );
}
  • Start fetching user details
  • Wait…
  • Finish fetching user details
  • Start fetching posts
  • Wait…
  • Finish fetching posts

fetch-then-render

// Kick off fetching as early as possible
const promise = fetchProfileData();

function ProfilePage() {
  const [user, setUser] = useState(null);
  const [posts, setPosts] = useState(null);

  useEffect(() => {
    promise.then(data => {
      setUser(data.user);
      setPosts(data.posts);
    });
  }, []);

  if (user === null) {
    return <p>Loading profile...</p>;
  }
  return (
    <>
      <h1>{user.name}</h1>
      <ProfileTimeline posts={posts} />
    </>
  );
}

// The child doesn't trigger fetching anymore
function ProfileTimeline({ posts }) {
  if (posts === null) {
    return <h2>Loading posts...</h2>;
  }
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.text}</li>
      ))}
    </ul>
  );
}
  • Start fetching user details
  • Start fetching posts
  • Wait…
  • Finish fetching user details
  • Finish fetching posts

Render-as-You-Fetch

// This is not a Promise. It's a special object from our Suspense integration.
const resource = fetchProfileData();

function ProfilePage() {
  return (
    <Suspense fallback={<h1>Loading profile...</h1>}>
      <ProfileDetails />
      <Suspense fallback={<h1>Loading posts...</h1>}>
        <ProfileTimeline />
      </Suspense>
    </Suspense>
  );
}

function ProfileDetails() {
  // Try to read user info, although it might not have loaded yet
  const user = resource.user.read();
  return <h1>{user.name}</h1>;
}

function ProfileTimeline() {
  // Try to read posts, although they might not have loaded yet
  const posts = resource.posts.read();
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.text}</li>
      ))}
    </ul>
  );
}
  • Render <ProfileDetails>
    • It calls resource.user.read()
    • None of the data is fetched yet, so this component “suspends”
    • React skips over it, and tries rendering other components
  • Render <ProfileTimeline>
    • It calls resource.posts.read()
    • No data yet, so this component also “suspends”
    • React skips over it too, and tries rendering other components
  • Nothing left to try rendering
    • <ProfileDetails> suspended, React shows the closest <Suspense> fallback: <h1>Loading profile...</h1>
    • Done for now.

What is concurrent mode?

useDeferredValue

SuspenseList

useTransition

Recoil

Be the first to comment

Leave a Reply

Your email address will not be published.


*