React – What’s concurrent mode (1)?

Suspense

fetch-on-render

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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>
);
}
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> ); }
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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>
);
}
// 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> ); }
// 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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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>
);
}
// 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> ); }
// 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.


*