This article from a small point, thinking about, a look at a thousand lines under the hook source code. Then came the React Ban, just like Harry Potter’s Apparition Charm.
Are you okay? It takes getting used to. “– Albus Dumbledore
Story
1. Origin
The following components, a, B, C judgment condition to write three, how to write?
export const Origin: React.FC = () = > {
const a = true;
const b = true;
const c = true;
return (
<div>
{(a || b || c) && (
<div>
<h5>title</h5>
{a && <div>a</div>}
{b && <div>b</div>}
{c && <div>c</div>}
</div>
)}
</div>
);
};
Copy the code
2. A. children B. children C. children
Check ReactChildNode as follows, if all are empty, return NULL. Don’t need to write it again all the conditions a | b | | | c.
Look before you leap, it looks a lot more complicated than the original code
const Wrapper: React.FC = ({ children }) = > {
const children = (props as any)? .childrenconsole.info('children', children)
if (
!children ||
(Array.isArray(children) && children.every((item) = >! item)) ) {return null
}
return (
<div>
<h5>title</h5>
{children}
</div>)}export const V1: React.FC = () = > {
const a = true
const b = false
const c = false
return (
<Wrapper>
{a && <div>a</div>}
{b && <div>b</div>}
{c && <div>c</div>}
</Wrapper>)}Copy the code
3. When DO I encounter an empty component?
I think I can still judge.
const Null: React.FC = () = > null
export const V2: React.FC = () = > {
return (
<Wrapper>
<Null />
<Null />
</Wrapper>)}Copy the code
The React Node is a function. I’ll run it
Console. info(
As a result,
const Wrapper: React.FC = ({ children }) = > {
const children = (props as any)? .childrenconsole.info('children', children)
if (
!children ||
(Array.isArray(children) && children.every((item) = > {
if(! item) {return true
}
if(typeofitem? .type ==='function') {
return! item.type(item.props) }return false{})))return null
}
return (
<div>
<h5>title</h5>
{children}
</div>)}Copy the code
5 although can, hidden excellent huge, such as too<Null />
There are hooks
constNull: React.FC<{ hi? :string} > =({ hi = '_' }) = > {
useEffect(() = > {
console.info('null <--', hi)
return () = > {
console.info('null -->', hi)
}
}, [])
return null
}
Copy the code
[Figure 1. When I run, children are empty, can be filtered out, but run once]
[Figure 2. Run twice when I run, children not all empty]
6. Can I get a function to eliminate side effects? If I can, I’ll execute it ahead of time.
What is useEffect first? React/SRC/reacthooks.js# L95
@flow
export function useEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const dispatcher = resolveDispatcher()
return dispatcher.useEffect(create, deps)
}
Copy the code
What is a dispatcher? Will the results of useEffect calls exist on it? 🤔 ️
import ReactCurrentDispatcher from './ReactCurrentDispatcher';
function resolveDispatcher() {
return ReactCurrentDispatcher.current;
}
--- ./ReactCurrentDispatcher.js
const ReactCurrentDispatcher = {
current: (null: null | Dispatcher),
};
export default ReactCurrentDispatcher;
Copy the code
Gee, there’s an Export default, that’s fine
[Figure 1. I use the editor to type react.reactcu… and it says nothing.]
[Figure 2, I clicked node_modules/@types/react/index.d.ts full text search 🔍 ReactCurrentDispatcher, nothing]
[figure 3, I opened the node_modules/react/CJS/react. Development. The js, 🔍 search here!!]
var ReactSharedInternals = {
ReactCurrentDispatcher: ReactCurrentDispatcher,
...
};
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactSharedInternals;
Copy the code
Using this API will get you fired 🦑, 😯! Also, I can’t seem to get the return content
6.1 But, seeing.current, I had a second thought
I replace dispatcher.current with dispatcher.current during synchronous method execution. so
export const apparate = function (exec: () => any) {
const x = (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
const origin = x.ReactCurrentDispatcher.current
x.ReactCurrentDispatcher.current = new Proxy({}, {get: () = > () = > undefined,},)const result = exec()
x.ReactCurrentDispatcher.current = origin
return result
}
export const Wrapper: React.FC<T> = (props) = > {
const children = (props as any)? .childrenconsole.info('children', children)
if (
!children ||
(Array.isArray(children) &&
children.every((item) = > {
if(! item) {return true
}
if (typeofitem? .type ==='function') {
try {
return! apparate(() = > item.type(item.props))
} catch (error) {
console.warn(' execute error')
return false}}return false{})))return null
}
return (
<div>
<h5>title</h5>
{children}
</div>)}Copy the code
👀 see, when executing function Component function, apparate in place.
[Figure 1. I execute code, children empty, not execute]
[Figure 2. I execute code, children are not empty, execute once]
Okay, better than expected, better than the planned active elimination of side effects
After the
Play
Encapsulate and play
My Style:
/** Deletrius, if the child element is empty, it disappears */
export function selfOffHoc<T> (Wrapper: React.FC<T>) {
const SelfOffWrapper: React.FC<T> = (props) = > {
const children = (props as any)? .childrenif (
[].concat(children).every((item: any) = > {
if(! item) {return true
}
if (typeofitem? .type ==='function') {
try {
return! apparate(() = > item.type(item.props))
} catch (error) {
console.warn(' execute error')
return false}}return false{}))return null
}
return <Wrapper {. props} >{children}</Wrapper>
}
return SelfOffWrapper
}
Copy the code
Usage:
// const ExtraWrapper: React.FC<{ loading? : boolean }> = ...
constExtraWrapper = selfOffHoc<{ loading? :boolean} > (({ children }) = > (
<View style={{ marginRight: '0px' }}>
<View>Below:</View>
<View>{children}</View>
</View>
))
// Above, there seems to be no lock in the conventional way
export default function () {
return (
<ExtraWrapper>
{null && <a>1</a>}
{false && <b>2</b>}
{0 && <code>3</code>}
<Null />
</ExtraWrapper>)}Copy the code
Rachel:
- This method can be used to reduce the judgment condition of redundant one time for purely demonstrative components and components without side effects
- If the useEffect changes its state, it is not applicable
Bonus tip — Don’t do it in… Challenge it on the shoulder of _BE_FIRED and do itAsync Apparition
– will probably write a whole set of anti-React hooks, maybe pass by@vue/reactivity
.
“It does not to dwell on dreams, and forget to live.” — Dumbledore
You can’t live in dreams, Harry. Don’t rely on them and forget to live. — Dumbledore