-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
346 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
const rl = require("readline").createInterface({ input: process.stdin }); | ||
var iter = rl[Symbol.asyncIterator](); | ||
const readline = async () => (await iter.next()).value; | ||
|
||
async function fn1() { | ||
/** | ||
* | ||
* @param {number} emptyCount | ||
*/ | ||
function getGapWater(emptyCount, fullCount = 0) { | ||
if (emptyCount < 2) return fullCount; | ||
const rest = emptyCount % 3; | ||
const currentCount = parseInt(emptyCount / 3); | ||
if (rest + currentCount === 2) return currentCount + fullCount + 1; | ||
return getGapWater(rest + currentCount, fullCount + currentCount); | ||
} | ||
|
||
while ((line = await readline())) { | ||
if (line == 0) break; | ||
console.log(getGapWater(line)); | ||
} | ||
} | ||
async function fn2() { | ||
// Write your code here | ||
let nums = []; | ||
while ((line = await readline())) { | ||
nums.push(Number(line)); | ||
} | ||
nums.shift(); | ||
nums = nums.reduce((unRepeatNums, num) => { | ||
if (unRepeatNums.length === 0) { | ||
unRepeatNums.push(num); | ||
return unRepeatNums; | ||
} | ||
if (!unRepeatNums.includes(num)) { | ||
// unRepeatNums.push(num); | ||
let start = 0; | ||
let end = unRepeatNums.length - 1; | ||
let mid = (start + end) >> 1; | ||
while (start <= end) { | ||
mid = (start + end) >> 1; | ||
if (unRepeatNums[mid] > num) { | ||
end = mid - 1; | ||
} else { | ||
start = mid + 1; | ||
} | ||
} | ||
// let i = 0; | ||
// for (; i < unRepeatNums.length; i++) { | ||
// if (unRepeatNums[i] > num) { | ||
// i; | ||
// break; | ||
// } | ||
// } | ||
unRepeatNums.splice(start + 1, 0, num); | ||
} | ||
return unRepeatNums; | ||
}, []); | ||
for (const num of nums) { | ||
console.log(num); | ||
} | ||
} | ||
|
||
async function fn3() { | ||
const changeMap = { | ||
A: 10, | ||
B: 11, | ||
C: 12, | ||
D: 13, | ||
E: 14, | ||
F: 15, | ||
}; | ||
while ((line = await readline())) { | ||
let count = 0; | ||
currentTime = 1; | ||
for (let i = line.length - 1; i >= 2; i--) { | ||
count += Number(changeMap[line[i]] || line[i]) * currentTime; | ||
currentTime = currentTime * 16; | ||
} | ||
console.log(count); | ||
} | ||
} | ||
|
||
async function a() { | ||
// Write your code here | ||
let nums = []; | ||
while ((line = await readline())) { | ||
nums.push(Number(line)); | ||
} | ||
nums.shift(); | ||
nums = nums.reduce((unRepeatNums, num) => { | ||
if (unRepeatNums.length === 0) { | ||
unRepeatNums.push(num); | ||
return unRepeatNums; | ||
} | ||
if (!unRepeatNums.includes(num)) { | ||
// unRepeatNums.push(num); | ||
let i = 0; | ||
for (; i < unRepeatNums.length; i++) { | ||
if (unRepeatNums[i] > num) { | ||
break; | ||
} | ||
} | ||
|
||
unRepeatNums.splice(i, 0, num); | ||
} | ||
return unRepeatNums; | ||
}, []); | ||
for (const num of nums) { | ||
console.log(num); | ||
} | ||
} | ||
|
||
async function ss() { | ||
// Write your code here | ||
while ((line = await readline())) { | ||
const countMap = new Map(); | ||
// 获取各个字符串的计数 | ||
for (let i = 0; i < line.length; i++) { | ||
const char = line[i]; | ||
if (!countMap.has(char)) { | ||
countMap.set(char, 1); | ||
} else { | ||
countMap.set(char, countMap.get(char) + 1); | ||
} | ||
} | ||
// 找出最小的那个 迭代 Map | ||
const entries = Array.from(countMap.entries()).sort((a, b) => a[1] - b[1]); | ||
// 有重复 | ||
const [_, minCount] = entries[0]; | ||
for (const entry of entries) { | ||
if (entry[1] === minCount) { | ||
line = line.replace(new RegExp(entry[0], "g"), ""); | ||
continue; | ||
} | ||
break; | ||
} | ||
console.log(line); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/** | ||
* | ||
* @param {number} number | ||
*/ | ||
function fn(number) { | ||
const str = number.toString(); | ||
let splitStr = ""; | ||
let count = 0; | ||
for (let i = str.length - 1; i >= 0; i--) { | ||
if (count === 3) { | ||
splitStr = "," + splitStr; | ||
count = 0; | ||
} | ||
splitStr = `${str[i]}${splitStr}`; | ||
count++; | ||
} | ||
return splitStr; | ||
} | ||
|
||
/** | ||
* | ||
* @param {number} number | ||
*/ | ||
function fn1(number) { | ||
const str = number.toString(); | ||
return str.replace(/\B(?=(\d{3})+)/g, ","); | ||
} | ||
|
||
/** | ||
* | ||
* @param {Record<string, any>} obj | ||
* @param {string|string[]} path | ||
* @param {any} defaultValue | ||
*/ | ||
function get(obj, path, defaultValue) { | ||
let value = obj; | ||
// 处理字符串路径 | ||
if (typeof path === "string") { | ||
const newPath = path.replace(/([^\.]+)\[([^\.]+)\]/g, "$1.$2"); | ||
newPath.split(".").every((path) => { | ||
try { | ||
value = value[path]; | ||
return true; | ||
} catch (e) { | ||
value = defaultValue; | ||
return false; | ||
} | ||
}); | ||
} | ||
return value === undefined ? defaultValue : value; | ||
} | ||
|
||
const testObj = { a: [{ b: { c: "6" } }], d: { e: 90 } }; | ||
|
||
console.log("--1", get(testObj, "a[2].b.c", "818")); | ||
// console.log("--2", get(testObj, "d.e")); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
# React Router 原理 | ||
|
||
React Router 是 React 官方提供的路由管理器,它可以帮助我们管理应用的路由,实现不同 URL 对应的不同组件的渲染。 | ||
|
||
## 工作原理 | ||
我们先看一段 React Router 的代码: | ||
|
||
```jsx | ||
import React from'react'; | ||
import { BrowserRouter as Router, Switch, Route } from'react-router-dom'; | ||
|
||
|
||
function App() { | ||
return ( | ||
<Router> | ||
<Switch> | ||
<Route exact path="/" component={Home} /> | ||
<Route path="/users" component={Users} /> | ||
<Route path="/users/:id" component={User} /> | ||
<Route path="/users/:id/edit" component={UserEdit} /> | ||
</Switch> | ||
</Router> | ||
); | ||
|
||
} | ||
|
||
export default App; | ||
``` | ||
|
||
|
||
React Router 的工作原理如下: | ||
|
||
1. 首先,我们需要定义好路由规则,比如我们有如下路由规则: | ||
|
||
|
||
``` | ||
/users | ||
/users/:id | ||
/users/:id/edit | ||
``` | ||
|
||
2. 然后,我们需要在应用的入口文件中,使用 React Router 的 `Router` 组件,将路由规则和对应的组件进行绑定。 | ||
|
||
3. 当用户访问 `/users` 页面时,React Router 会匹配到对应的路由规则,并渲染 `Users` 组件。 | ||
|
||
4. 当用户访问 `/users/:id` 页面时,React Router 会匹配到对应的路由规则,并渲染 `User` 组件,并将 `:id` 作为参数传递给 `User` 组件。 | ||
|
||
5. 当用户访问 `/users/:id/edit` 页面时,React Router 会匹配到对应的路由规则,并渲染 `UserEdit` 组件,并将 `:id` 作为参数传递给 `UserEdit` 组件。 | ||
|
||
React Router 的路由匹配规则是基于路径的,因此,我们需要确保路径的正确性。 | ||
|
||
6. 当用户访问 `/users/123/edit` 页面时,React Router 会匹配到 `/users/:id/edit` 路由规则,并渲染 `UserEdit` 组件,并将 `123` 作为参数传递给 `UserEdit` 组件。 | ||
|
||
|
||
## 代码实现 | ||
|
||
### 1. Router 组件 | ||
|
||
`Router` 组件是 React Router 的核心组件,它负责管理应用的路由,并渲染对应的组件。 | ||
|
||
```jsx | ||
export default class BrowserRouter extends React.Component { | ||
constructor(props) { | ||
this.history = createBrowserHistory(); | ||
} | ||
render() { | ||
const | ||
return ( | ||
<RouterContext.Provider value={{history: this.history, location: this.history.location, staticContext: undefined}}> | ||
{this.props.children} | ||
</RouterContext.Provider> | ||
); | ||
} | ||
} | ||
|
||
``` | ||
|
||
### 2.Route 组件 | ||
|
||
```jsx | ||
export default class Route extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
match: props.computeMatch(props.location.pathname) | ||
}; | ||
} | ||
componentDidMount() { | ||
const { history } = this.props; | ||
const unlisten = history.listen((location) => { | ||
this.setState({ | ||
match: this.props.computeMatch(location.pathname) | ||
}); | ||
}); | ||
this.setState({ | ||
unlisten | ||
}); | ||
} | ||
componentWillUnmount() { | ||
this.state.unlisten(); | ||
} | ||
render() { | ||
const { component: Component, render, children,computedMatch } = this.props; | ||
if (!computedMatch) { | ||
return null; | ||
} | ||
|
||
const match = computedMatch|| matchPath(this.props.location.pathname, this.props); | ||
if (match) { | ||
if (Component) { | ||
return <Component {...this.props} />; | ||
} else if (render) { | ||
return render({...this.props, match }); | ||
} else if (children) { | ||
return children({...this.props, match }); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
} | ||
``` | ||
### 3.Switch 组件 | ||
|
||
```jsx | ||
export default class Switch extends React.Component { | ||
render() { | ||
const { location, children } = this.props; | ||
let match = null; | ||
React.Children.forEach(children, (element) => { | ||
// 如果没有 match 才执行计算 | ||
if (match == null && React.isValidElement(element)) { | ||
const { path, exact, strict, sensitive, from } = element.props; | ||
const pathname = getFullPath(location.pathname, from); | ||
if (path) { | ||
match = matchPath(pathname, { path, exact, strict, sensitive }); | ||
} else { | ||
match = pathMatch(pathname); | ||
} | ||
} | ||
}); | ||
return match ? React.cloneElement(React.Children.only(children), { computedMatch: match }) : null; | ||
} | ||
} | ||
``` | ||
|
||
|
||
|
||
## 总结 | ||
Router 组件是负责上下文的注入,还有统一前缀等配置,Route 组件可以根据 path 进行匹配,并且内部提供了 compuMatch 方法,由外部控制是否渲染,Switch 组件可以根据路由匹配到的第一个组件进行渲染。 |