({ children, ...props })
| 142 | */ |
| 143 | |
| 144 | export const Router = ({ children, ...props }) => { |
| 145 | // the router we will inherit from - it is the closest router in the tree, |
| 146 | // unless the custom `hook` is provided (in that case it's the default one) |
| 147 | const parent_ = useRouter(); |
| 148 | const parent = props.hook ? defaultRouter : parent_; |
| 149 | |
| 150 | // holds to the context value: the router object |
| 151 | let value = parent; |
| 152 | |
| 153 | // when `ssrPath` contains a `?` character, we can extract the search from it. |
| 154 | // also, ensure ssrSearch is always defined when ssrPath is provided, so that |
| 155 | // useSearch behavior matches usePathname (proper SSR hydration when client |
| 156 | // renders <Router> without props after server rendered with ssrPath/ssrSearch) |
| 157 | const [path, search = props.ssrSearch ?? ""] = |
| 158 | props.ssrPath?.split("?") ?? []; |
| 159 | if (path) (props.ssrSearch = search), (props.ssrPath = path); |
| 160 | |
| 161 | // hooks can define their own `href` formatter (e.g. for hash location) |
| 162 | props.hrefs = props.hrefs ?? props.hook?.hrefs; |
| 163 | |
| 164 | // hooks can define their own search hook (e.g. for memory location) |
| 165 | props.searchHook = props.searchHook ?? props.hook?.searchHook; |
| 166 | |
| 167 | // what is happening below: to avoid unnecessary rerenders in child components, |
| 168 | // we ensure that the router object reference is stable, unless there are any |
| 169 | // changes that require reload (e.g. `base` prop changes -> all components that |
| 170 | // get the router from the context should rerender, even if the component is memoized). |
| 171 | // the expected behaviour is: |
| 172 | // |
| 173 | // 1) when the resulted router is no different from the parent, use parent |
| 174 | // 2) if the custom `hook` prop is provided, we always inherit from the |
| 175 | // default router instead. this resets all previously overridden options. |
| 176 | // 3) when the router is customized here, it should stay stable between renders |
| 177 | let ref = useRef({}), |
| 178 | prev = ref.current, |
| 179 | next = prev; |
| 180 | |
| 181 | for (let k in parent) { |
| 182 | const option = |
| 183 | k === "base" |
| 184 | ? /* base is special case, it is appended to the parent's base */ |
| 185 | parent[k] + (props[k] ?? "") |
| 186 | : props[k] ?? parent[k]; |
| 187 | |
| 188 | if (prev === next && option !== next[k]) { |
| 189 | ref.current = next = { ...next }; |
| 190 | } |
| 191 | |
| 192 | next[k] = option; |
| 193 | |
| 194 | // the new router is no different from the parent or from the memoized value, use parent |
| 195 | if (option !== parent[k] || option !== value[k]) value = next; |
| 196 | } |
| 197 | |
| 198 | return h(RouterCtx.Provider, { value, children }); |
| 199 | }; |
| 200 | |
| 201 | const h_route = ({ children, component }, params) => { |
nothing calls this directly
no test coverage detected
searching dependent graphs…