0

I want to use react suspense.

The suspense behavior I want is to not show the fallback until a certain amount of time.

Using react with next works as intended. However, react alone flickers.

Why does this only work when using next ?

What's the difference?

After changing the react dom generation code, it worked as expected.

How can I do this in react-native as well?

Example

I made a simple todo app.

We made a 100ms delay to get the todos list with an asynchronous request.

recoil

import { selector, atom } from "recoil";

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

export const todosDelayState = selector({
  key: "todosDelayState",
  get: async ({ get }) => {
    await sleep(100);
    const todos = get(todosState);

    return todos;
  }
});

export const todosState = atom({
  key: "todosState", // unique ID (with respect to other atoms/selectors)
  default: [{ id: 0, text: "fasfasdf", done: false }] // default value (aka initial value)
});

Home

export default function Home({ accounts }) {
  return (
    <RecoilRoot>
      <React.Suspense fallback={<span>Loading</span>}>
        <Todo />
      </React.Suspense>
    </RecoilRoot>
  );
}

Todo

import TodoForm from "./TodoForm";
import TodoList from "./TodoList";
import React from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import { todosDelayState, todosState } from "./todos";

function Todo() {
  const [_, setTodos] = useRecoilState(todosState);
  const todos = useRecoilValue(todosDelayState);

  const onToggle = (id, done) => {
    const _todos = todos.map((todo) => {
      if (todo.id === id) {
        return { ...todo, done: !done };
      } else {
        return todo;
      }
    });
    setTodos(_todos);
  };

  const onRemove = (id) => {
    const _todos = todos.filter((todo) => {
      return todo.id === id ? false : true;
    });
    setTodos(_todos);
  };

  const onInsert = (value) => {
    const id = todos.length === 0 ? 1 : todos[todos.length - 1].id + 1;
    const todo = {
      id,
      text: value,
      done: false
    };
    const _todos = todos.concat([todo]);
    setTodos(_todos);
  };
  return (
    <React.Fragment>
      <TodoForm onInsert={onInsert} />
      <TodoList todos={todos} onToggle={onToggle} onRemove={onRemove} />
    </React.Fragment>
  );
}

export default Todo;

1. Sandbox with next, react 18, recoil

live demo

In case it behaves exactly as I expected.

enter image description here

2. Sandbox with react 18, recoil

live demo

~~blinks~~ --> nice work

After changing the react dom generation code, it worked as expected.

import { StrictMode } from "react";
import ReactDOM from "react-dom";

import App from "./App";

// const rootElement = document.getElementById("root");
// ReactDOM.render(
//   <StrictMode>
//     <App />
//   </StrictMode>,
//   rootElement
// );

const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);

root.render(<App />);

enter image description here enter image description here

3. Expo with react-native, react, recoil

live demo solved live demo

~~blinks~~ -> work

Unlike react-dom, react-native could not find a code that directly affects it.

So, I made a custom hook, Suspense, and ErrorBoundary using the loadable of recoil.

export const useCustomRecoilValue = (state, initialValue) => {
  const data = useRecoilValueLoadable(state)
  const prevData = useRef(initialValue)

  const _data = useMemo(() => {
    if (data.state === 'hasValue') {
      prevData.current = data.contents
      return [data.contents, false, undefined]
    } else if (data.state === 'hasError') {
      return [prevData.current, false, data.contents]
    } else {
      return [prevData.current, true, undefined]
    }
  }, [data])

  return _data
}
// const todos = useRecoilValue(todosDelayState)
const [todos, loading, error] = useCustomRecoilValue(todosDelayState, [])

  // return (
  //   <VStack space={8} w="100%">
  //     <TodoForm onInsert={onInsert} />
  //     <TodoList todos={todos} onToggle={onToggle} onRemove={onRemove} />
  //   </VStack>
  // )
  return (
    <VStack space={8} w="100%">
      <TodoForm onInsert={onInsert} />
      <ErrorBoundary error={error} fallback={<Box>Error</Box>}>
        <Suspense
          delay={250}
          loading={loading}
          fallback={<Box>Loading...</Box>}>
          <TodoList todos={todos} onToggle={onToggle} onRemove={onRemove} />
        </Suspense>
      </ErrorBoundary>
    </VStack>
  )

enter image description here enter image description here

pruge
  • 31
  • 1
  • 4

0 Answers0