Skip to content

Instantly share code, notes, and snippets.

@dy
Last active November 5, 2019 17:54
Show Gist options
  • Save dy/51fd8a28fc0b97e43051b960b0ab02d9 to your computer and use it in GitHub Desktop.
Save dy/51fd8a28fc0b97e43051b960b0ab02d9 to your computer and use it in GitHub Desktop.
React concurrent mode flaw

React concurrent mode is flawed design workaround. That issue cannot happen with web-components.

Component itself must be responsible for its rendering content and loading state - putting loading logic into Suspense wrapper creates redundant waterfall.

const initialResource = fetchProfileData(0);

function App() {
  const [resource, setResource] = useState(initialResource);
  return (
    <>
      <button onClick={() => {
        const nextUserId = getNextId(resource.userId);
        setResource(fetchProfileData(nextUserId));
      }}>
        Next
      </button>
      <ProfilePage resource={resource} />
    </>
  );
}

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

function ProfileDetails({ resource }) {
  const user = resource.user.read();
  return <h1>{user.name}</h1>;
}

function ProfileTimeline({ resource }) {
  const posts = resource.posts.read();
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.text}</li>
      ))}
    </ul>
  );
}

must look like

const initialResource = fetchProfileData(0);

function App() {
  const [resource, setResource] = useState(initialResource);
  return (
    <>
      <button onClick={() => {
        const nextUserId = getNextId(resource.userId);
        setResource(fetchProfileData(nextUserId));
      }}>
        Next
      </button>
      <ProfilePage resource={resource} />
    </>
  );
}

function ProfilePage({ resource }) {
  return (<>
    <ProfileDetails resource={resource} />
    <ProfileTimeline resource={resource} />
  </>);
}

function ProfileDetails({ resource }) {
  const user = resource.user.read();
  return loading ? <h1>Loading...</h1> : <h1>{user.name}</h1>;
}

function ProfileTimeline({ resource }) {
  const posts = resource.posts.read();
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.text}</li>
      ))}
    </ul>
  );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment