preface
Recently, I have been thinking about how to write React in the most comfortable way. From the tedious Redux to Context at the beginning, the data communication between components at the same level has gradually become simpler, but sometimes I also write redundant code, which makes me wonder again how to make the simple communication between components more pure
State of ascension
The recent project is doing background management, simple page often need such a situation, simple page is a query form, a table of results
const Page = (a)= > {
return (
<Container>
<SearchForm />
<ResultTable />
</Container>
);
};
Copy the code
The function is also very simple, query form input criteria, table display results, this is one-way communication of the component, that is, form criteria => query table, but because it is a peer component, have to state up
And when I go up, it looks like this
const Page = (a)= > {
const [params,setParams] = useState();
return (
<Container>
<SearchForm setParams={setParams}/>
<ResultTable params={params}/>
</Container>
);
};
Copy the code
This works, but there is something extra. If you use data flow methods like Redux and Context, you don’t need to pass extra parameters, but there are more tedious steps
Triggered component refreshes
This name is a made-up one, but what I want to say is that
says
you have to re-request data, and
will re-request data
The first idea is that using the SWR library, the table component must request an interface. If the request is made using SWR, the table component can be refreshed using a trigger(‘/ API /tableList’) on any component, even if it is not in the component
So what about native, which is pretty simple, publish subscribe, rewrite components
const SearchForm = (a)= > {
// Triggers the research event
emitter.emit('research', { time: 'now' });
// ...
};
const ResultTable = (a)= > {
// When the research event is triggered
emitter.on('research', ({ time }) => getList(time));
// ...
};
Copy the code
This way, just like THE trigger component refresh I was thinking of, anywhere research is triggered, the results table will show the latest results
This approach is often used. Redux, for example, is implemented in a similar observer mode. Connect components subscribe to store updates, and each store update notifies the components to refresh and obtain new states
How does Emitter work
There are a lot of such libraries, WHAT I found is mitt written by the big guy of Preact, the source code is very short, also very simple, directly post code analysis
// The type of event
export type EventType = string | symbol;
// The Handler can receive an optional event argument, but does not return any value
export type Handler = (event? :any) = > void;
// Wildcard Handler
export type WildcardHandler= (type: EventType, event? :any) = > void
// The Handler array that is currently registered
export type EventHandlerList = Array<Handler>;
export type WildCardEventHandlerList = Array<WildcardHandler>;
// A map of event types. Each event type has a corresponding handler list
export type EventHandlerMap = Map<EventType, EventHandlerList | WildCardEventHandlerList>;
export interface Emitter {
on(type: EventType, handler: Handler): void;
on(type: The '*', handler: WildcardHandler): void;
off(type: EventType, handler: Handler): void;
off(type: The '*', handler: WildcardHandler): void;
emit<T = any> (type: EventType, event? : T):void;
emit(type: The '*', event? :any) :void;
}
/** Mitt: Tiny (~200b) functional event emitter / pubsub. * @name mitt * @returns {Mitt} */
export default function mitt(all? : EventHandlerMap) :Emitter {
all = all || new Map();
return {
/ * * * for a given event type register an event handler. * @ param {string | symbol} type to monitor the event type, The wildcard "*" listens for all functions * @param {Function} handlers respond to the given event * @memberof mitt */
on(type: EventType, handler: Handler) {
// Get the map handler array for type
const handlers = all.get(type);
// Add a new one if there is one
const added = handlers && handlers.push(handler);
// No new handler array is added
if(! added) { all.set(type, [handler]); }},/ * * * removes a given event an event handler * @ param {string | symbol} type to remove the type of event handler, Or "*" * @param {Function} handler Removes the handler Function * @memberof mitt */
off(type: EventType, handler: Handler) {
const handlers = all.get(type);
if (handlers) {
// >>> 0 must be non-negative, the positive number stays the same, -1 becomes 4294967295
handlers.splice(handlers.indexOf(handler) >>> 0.1); }},/** * Triggers all handler functions of the given event type * if the event type exists, the handler of "*" will be executed after all handlers of the matching type are executed ** Note: Manually trigger the "*" is not supported by the * * @ param {string | symbol} type need to call the event type * @ param {Any} (evt) Any type of value, recommend the object type, Is passed to each handler handler function * @memberof mitt */
emit(type: EventType, evt: any) {
/ / slice a shallow copy, or remove https://github.com/developit/mitt/issues/65 there will be a problem
// Map instead of foreach because 4 letters are missing...
((all.get(type) | | []) as EventHandlerList).slice(a).map((handler) => { handler(evt); });
((all.get(The '*') | | []) as WildCardEventHandlerList).slice(a).map((handler) => { handler(type, evt); }); }}; }Copy the code
The library is so simple that it’s only 200 bytes and has few features, but it’s just enough
Like Redux-Thunk, which only has a dozen lines of code but 14.9K Star, it’s all bullshit
conclusion
I feel that I have always followed the rules, so it is very old-fashioned, this small thought made me feel that there are many variable things, but also very convenient
However, I think pubsub should be properly used for fast communication and can be used as a quick backup option. I also remembered that I wrote FLUTTER a long time ago. Since I did not use any state management library, I chose pubsub library like event_bus
There are too many components passing information, so you still need to choose a good state management library. I recently found a good pullState library, so I have a chance to give it a try