🤔 Anti-React paradigm thinking

This is a story triggered by loading

How to design a normal Loading

const App = () = > {
  return <>
     {/** DO SOME THING **/}
     <Loading />
    </>
}

const Loading = () = > {
  const { loadingVisible } = useStore()
  return loadingVisible ? 'Go round and round' : null
}

Copy the code

Loading state was defined in store, and store was changed by action, transform, mutation, change, etc., so that the React driver loading was displayed

This works well with the data-driven view, but it has the following problems

  1. The intuition is that we turn loading on and off rather than changing a state in the store

  2. Loading Is the initial loading of other pre-loaded resources, whether store or view

  3. In the store layer, if the store is placed at the top level, the state of the store will become complicated. If the store is scattered in the sub-stores, it will also face the problem of store management, although this problem is a common problem of state management

Anti-paradigm Loading

// file - loading.jsx
const Loading = () = > <>Turned around</>

export let loadingVisible = false

const loadingElm = document.createElement("div")

export function showLoading(){
  document.body.appendChild(loadingElm);
  ReactDOM.render(<Loading />, loadingElm);
  loadingVisible = true
}

export function hideLoading(){
  ReactDOM.unmountComponentAtNode(loadingElm);
  document.body.removeChild(loadingElm);
  loadingVisible = false
}

Copy the code

This approach is similar to manipulating the DOM directly to generate, of course, we can also use this method to achieve toast Alert some global generic components

The upside is that it becomes more intuitive imperative programming

Imperative React

What can we do if we take this notation even further

The Demo address codesandbox. IO/s/beautiful…

function confirmModal({ title = "", context }) {
  return new Promise((resolve, reject) = > {
    const div = document.createElement("div");
    document.body.appendChild(div);
    const close = () = >
      ReactDOM.unmountComponentAtNode(div) && document.body.removeChild(div);
    const onOk = () = > close() && resolve();
    const onCancel = () = > close() && reject();

    ReactDOM.render(
      <Modal title={title} visible={true} onOk={onOk} onCancel={onCancel}>
        {context}
      </Modal>,
      div
    );
  });
}

async function confirm() {
  // Test some
  try {
    await confirmModal({ title: "Confirmed or not".context: "Confirm information" });
    console.log("Confirm");
  } catch (error) {
    console.log("Cancel");
  }
}

ReactDOM.render(
  <div className="App">
    <Button onClick={confirm}>confirm</Button>
  </div>.document.getElementById("root"));Copy the code

Promise allows us to take some of the state controls that need to be written in local components and turn them into more intuitive imperative logic, and make the thread of business logic clearer

async function createItem() {
  // Test some
  const div = document.createElement("div");
  document.body.appendChild(div);
  const close = () = >
    ReactDOM.unmountComponentAtNode(div) && document.body.removeChild(div);
  const onFinish = async() = > {// await updates the interface
    close();
  };
  const onFinishFailed = () = > {
    // Error message
  };

  ReactDOM.render(
    <Modal title={"New"}visible={true} footer={null}>
      <Form
        name="basic"
        labelCol={{ span: 8 }}
        wrapperCol={{ span: 16 }}
        initialValues={{ remember: true }}
        onFinish={onFinish}
        onFinishFailed={onFinishFailed}
        autoComplete="off"
      >
        <Form.Item
          label="Username"
          name="username"
          rules={[{ required: true.message: "Please input your username!" }]}
        >
          <Input />
        </Form.Item>

        <Form.Item
          label="Password"
          name="password"
          rules={[{ required: true.message: "Please input your password!" }]}
        >
          <Input.Password />
        </Form.Item>

        <Form.Item wrapperCol={{ offset: 8.span: 16}} >
          <Button type="primary" htmlType="submit">submit</Button>
        </Form.Item>
      </Form>
    </Modal>,
    div
  );
}
Copy the code

React creates and destroys the logic that separates the current document flow

State management across trees

Since we created a new React node tree with reactdom. render, the original cross-node communication based on ReactContext would be invalid, so cross-node communication would be required

External state management can be done directly through things like React-Redux

Demo: codesandbox. IO/s/vibrant – s…

import { Provider } from "react-redux";

<Provider store={reduxStore}>{/* Mainline business */}<App />
</Provider>


<Provider store={reduxStore}>{/* The component of what we are currently doing */}<DoSomeThing />
</Provider>

Copy the code

Of course, it is possible to directly embed the store of the mainline business to complete the communication, but in many cases it is too heavy, because it is wrapped in a layer

Then I found some React state management libraries for a reference list

The following approach to cross-tree cross-component communication is designed by creating a hidden React Tree that wraps around a set of hooks or hooks and shares them with the consuming component

The demo codesandbox. IO/s/goofy – kil…



/** * Create cross component cross tree communication Hooks Create a hidden React Tree to wrap Hook * 2. When hiding React Tree renderers, update the hijacked Hook data *@param {Function} Hook Custom useHooks */

export const createHookObserver = (hook) = > {
  const div = document.createElement("div");
  const events = new Set(a);let $data;
  const update = (data) = > {
    $data = data;
    events.forEach((event) = > event(data));
    return null;
  };

  render(
    createElement(() = > update(hook())),
    div
  );
  const useHooks = () = > {
    const [val, setVal] = useState($data);
    useEffect(() = > {
      events.add(setVal);
      return () = >events.delete(setVal); } []);return val;
  };

  return useHooks;
};


const useCount = createHookObserver(() = > {
  const [count, setCount] = useState(0);
  return { count, setCount };
});

Copy the code

React Design

In React, the component is actually a state machine that deduces the view state in the current state by defining state.

The React component is designed to define states and describe abstractions between logic and reality.

We can see the beauty of less is more simplicity in React component design, but circling back, software engineering has no silver bullet.

How should we choose between logical and practical problems that cannot or are inconvenient to be solved by simple and tense description like React

Fundamentalism, paradigms, under what circumstances should these constraints be broken

End

Let’s think outside the box. We use this tool, this concept to solve our specific problem. It shouldn’t be limited by these things.