🤔 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
-
The intuition is that we turn loading on and off rather than changing a state in the store
-
Loading Is the initial loading of other pre-loaded resources, whether store or view
-
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.