ahooks#useUpdate TypeScript Examples
The following examples show how to use
ahooks#useUpdate.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: use-url-state.ts From bext with MIT License | 7 votes |
useUrlState = <S extends UrlState = UrlState>(
initialState?: S | (() => S),
options?: Options,
) => {
type State = Partial<{ [key in keyof S]: any }>;
const { navigateMode = 'push' } = options || {};
const history = useHistory();
const update = useUpdate();
const initialStateRef = useRef(
typeof initialState === 'function'
? (initialState as () => S)()
: initialState || {},
);
const queryFromUrl = useMemo(() => {
return parse(location.search, parseConfig);
}, [location.search]);
const targetQuery: State = useMemo(
() => ({
...initialStateRef.current,
...queryFromUrl,
}),
[queryFromUrl],
);
const setState = (s: React.SetStateAction<State>) => {
const newQuery = typeof s === 'function' ? s(targetQuery) : s;
update();
history[navigateMode]({
hash: location.hash,
search: stringify({ ...queryFromUrl, ...newQuery }, parseConfig) || '?',
});
};
return [targetQuery, useMemoizedFn(setState)] as const;
}
Example #2
Source File: useSpreadSheet.ts From S2 with MIT License | 4 votes |
export function useSpreadSheet(props: SheetComponentsProps) {
const forceUpdate = useUpdate();
const s2Ref = React.useRef<SpreadSheet>();
const containerRef = React.useRef<HTMLDivElement>();
const wrapperRef = React.useRef<HTMLDivElement>();
const {
spreadsheet: customSpreadSheet,
dataCfg,
options,
themeCfg,
sheetType,
onSheetUpdate = identity,
} = props;
/** 保存重渲 effect 的 deps */
const updatePrevDepsRef = React.useRef<[S2DataConfig, S2Options, ThemeCfg]>([
dataCfg,
options,
themeCfg,
]);
const { loading, setLoading } = useLoading(s2Ref.current, props.loading);
const pagination = usePagination(s2Ref.current, props);
useEvents(props, s2Ref.current);
const renderSpreadSheet = React.useCallback(
(container: HTMLDivElement) => {
const s2Options = getSheetComponentOptions(options);
const s2Constructor: S2Constructor = [container, dataCfg, s2Options];
if (customSpreadSheet) {
return customSpreadSheet(...s2Constructor);
}
if (sheetType === 'table') {
return new TableSheet(container, dataCfg, s2Options);
}
return new PivotSheet(container, dataCfg, s2Options);
},
[sheetType, options, dataCfg, customSpreadSheet],
);
const buildSpreadSheet = React.useCallback(() => {
setLoading(true);
s2Ref.current = renderSpreadSheet(containerRef.current);
s2Ref.current.setThemeCfg(props.themeCfg);
s2Ref.current.render();
setLoading(false);
// 子 hooks 内使用了 s2Ref.current 作为 dep
// forceUpdate 一下保证子 hooks 能 rerender
forceUpdate();
props.getSpreadSheet?.(s2Ref.current);
}, [props, renderSpreadSheet, setLoading, forceUpdate]);
// init
React.useEffect(() => {
buildSpreadSheet();
return () => {
s2Ref.current.destroy();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// 重渲 effect:dataCfg, options or theme changed
useUpdateEffect(() => {
const [prevDataCfg, prevOptions, prevThemeCfg] = updatePrevDepsRef.current;
updatePrevDepsRef.current = [dataCfg, options, themeCfg];
let reloadData = false;
let reBuildDataSet = false;
if (!Object.is(prevDataCfg, dataCfg)) {
reloadData = true;
s2Ref.current?.setDataCfg(dataCfg);
}
if (!Object.is(prevOptions, options)) {
if (!Object.is(prevOptions?.hierarchyType, options?.hierarchyType)) {
// 自定义树目录需要重新构建 CustomTreePivotDataSet
reBuildDataSet = true;
reloadData = true;
s2Ref.current?.setDataCfg(dataCfg);
}
s2Ref.current?.setOptions(options);
s2Ref.current?.changeSheetSize(options.width, options.height);
}
if (!Object.is(prevThemeCfg, themeCfg)) {
s2Ref.current?.setThemeCfg(themeCfg);
}
/**
* onSheetUpdate 交出控制权
* 由传入方决定最终的 render 模式
*/
const renderOptions = onSheetUpdate({
reloadData,
reBuildDataSet,
});
s2Ref.current?.render(renderOptions.reloadData, {
reBuildDataSet: renderOptions.reBuildDataSet,
});
}, [dataCfg, options, themeCfg, onSheetUpdate]);
useResize({
s2: s2Ref.current,
container: containerRef.current,
wrapper: wrapperRef.current,
adaptive: props.adaptive,
});
return {
s2Ref,
containerRef,
wrapperRef,
loading,
setLoading,
pagination,
};
}
Example #3
Source File: YakBatchExecutors.tsx From yakit with GNU Affero General Public License v3.0 | 4 votes |
BugTestExecutor: React.FC<YakBatchExecutorsProp> = (props) => {
const update = useUpdate()
const [listHeight, setListHeight] = useState<number>(500)
const [params, setParams] = useState<ExecBatchYakScriptParams>({
Concurrent: 5,
Keyword: props.keyword.split("-")[0],
Limit: 10000,
Target: props.sendTarget ? JSON.parse(props.sendTarget).join(",") : "",
DisableNucleiWorkflow: true,
ExcludedYakScript: [
"[fingerprinthub-web-fingerprints]: FingerprintHub Technology Fingerprint",
"[tech-detect]: Wappalyzer Technology Detection"
],
TotalTimeoutSeconds: 180,
Type: "nuclei"
})
const [totalLoading, setTotalLoading] = useState(true)
const [tasks, setTasks, getTasks] = useGetState<ExecBatchYakScriptTask[]>([])
const [filterTasks, setFilterTasks, getFilterTasks] = useGetState<ExecBatchYakScriptTask[]>([])
const [error, setError] = useState("")
const [token, setToken] = useState("")
const [executing, setExecuting] = useState(false)
const [checked, setChecked] = useState<boolean>(false)
const [uploadLoading, setUploadLoading] = useState(false)
const containerRef = useRef(null)
const wrapperRef = useRef(null)
const listRef = useRef(null)
const filterContainerRef = useRef(null)
const filterWrapperRef = useRef(null)
const [list] = useVirtualList(getTasks(), {
containerTarget: containerRef,
wrapperTarget: wrapperRef,
itemHeight: 50,
overscan: 5
})
const [filterList] = useVirtualList(getFilterTasks(), {
containerTarget: filterContainerRef,
wrapperTarget: filterWrapperRef,
itemHeight: 50,
overscan: 5
})
window.onresize = () => {
let timer: any = null
window.onresize = () => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
if (!listRef || !listRef.current) return
const list = listRef.current as unknown as HTMLDivElement
setListHeight(list.clientHeight - 10)
}, 50)
}
}
useEffect(() => {
setTimeout(() => {
if (!listRef || !listRef.current) return
const list = listRef.current as unknown as HTMLDivElement
setListHeight(list.clientHeight - 10)
}, 600)
return () => {
window.onresize = null
}
}, [])
useEffect(() => {
let timer = setTimeout(() => {
update()
}, 100)
return () => {
clearTimeout(timer)
}
}, [listHeight])
useEffect(() => {
setTotalLoading(true)
setTimeout(() => setTotalLoading(false), 500)
const token = randomString(40)
setToken(token)
setTasks([])
setParams({...params, Keyword: props.keyword.split("-")[0]})
const tempTasks = new Map<string, ExecBatchYakScriptTask>()
const updateTasks = () => {
let items: ExecBatchYakScriptTask[] = []
tempTasks.forEach((v, k) => {
items.push(v)
})
setTasks(items.sort((a, b) => b.Id.localeCompare(a.Id)))
}
const dataChannel = `${token}-exec-batch-yak-script-data`
const errorChannel = `${token}-exec-batch-yak-script-error`
const endChannel = `${token}-exec-batch-yak-script-end`
let updateTableTick = setInterval(updateTasks, 1000)
ipcRenderer.on(dataChannel, async (e: any, data: ExecBatchYakScriptResult) => {
if (data.ProgressMessage) {
return
}
let element = tempTasks.get(data.Id)
if (element === undefined) {
tempTasks.set(data.Id, {
Id: data.Id,
PoC: data.PoC,
Results: [],
Status: data.Status,
progress: 0
})
// updateTasks()
return
} else {
element.Status = data.Status
if (!element.Ok) {
element.Ok = data.Ok || false
}
element.Reason = data.Reason
if (data.Result) {
element.Results.push({...data.Result})
}
// updateTasks()
return
}
})
ipcRenderer.on(errorChannel, (e: any, error: any) => {
setError(error)
})
ipcRenderer.on(endChannel, (e: any, data: any) => {
info("模块加载完成 / 执行完毕")
setExecuting(false)
updateTasks()
})
ipcRenderer.invoke(
"exec-batch-yak-script",
{...params, Keyword: props.keyword.split("-")[0], Target: ""},
token
)
setExecuting(true)
return () => {
clearInterval(updateTableTick)
ipcRenderer.invoke("cancel-exec-batch-yak-script", token)
ipcRenderer.removeAllListeners(dataChannel)
ipcRenderer.removeAllListeners(errorChannel)
ipcRenderer.removeAllListeners(endChannel)
}
}, [props.keyword])
// 转换task内的result数据
const convertTask = (task: ExecBatchYakScriptTask) => {
// @ts-ignore
const results: ExecResult[] = task.Results
const messages: ExecResultMessage[] = []
for (let item of results) {
if (!item.IsMessage) continue
try {
const raw = item.Message
const obj: ExecResultMessage = JSON.parse(Buffer.from(raw).toString("utf8"))
messages.push(obj)
} catch (e) {
console.error(e)
}
}
return messages
}
useEffect(() => {
if (checked) {
const filters: ExecBatchYakScriptTask[] = getTasks()
.filter((item) => item.Results.length !== 0)
.filter(
(item) =>
(
convertTask(item)
.filter((e) => e.type === "log")
.map((i) => i.content)
.sort((a: any, b: any) => a.timestamp - b.timestamp) as ExecResultLog[]
).filter((i) => ["json", "success"].includes((i?.level || "").toLowerCase())).length > 0
)
setFilterTasks(filters)
} else {
setFilterTasks([])
}
}, [checked])
useEffect(() => {
if (tasks) {
const filters: ExecBatchYakScriptTask[] = getTasks()
.filter((item) => item.Results.length !== 0)
.filter(
(item) =>
(
convertTask(item)
.filter((e) => e.type === "log")
.map((i) => i.content)
.sort((a: any, b: any) => a.timestamp - b.timestamp) as ExecResultLog[]
).filter((i) => ["json", "success"].includes((i?.level || "").toLowerCase())).length > 0
)
if (JSON.stringify(filterTasks) !== JSON.stringify(filters)) setFilterTasks(filters)
}
}, [tasks])
if (totalLoading) {
return (
<div style={{textAlign: "center", width: "100%", marginTop: 100}}>
<Spin>正在加载专用漏洞库</Spin>
</div>
)
}
return (
<div className='bug-test-container'>
<Row>
<Col span={3}></Col>
<Col span={18}>
<Form
style={{textAlign: "center"}}
onSubmitCapture={(e) => {
e.preventDefault()
if (tasks.length === 0) {
Modal.error({title: "模块还未加载,请点击右上角配置进行YAML POC更新"})
return
}
if (!params.Target) {
Modal.error({title: "检测目标不能为空"})
return
}
if (!params.Keyword) {
Modal.error({title: "无 PoC 关键字选择"})
return
}
if (!token) {
Modal.error({title: "BUG:无 Token 生成,请重新打开该页"})
}
ipcRenderer.invoke("exec-batch-yak-script", params, token)
setExecuting(true)
setChecked(false)
}}
>
<Space style={{width: "80%"}} direction={"vertical"}>
<Spin spinning={uploadLoading}>
<ContentUploadInput
type="textarea"
beforeUpload={(f) => {
if (f.type !== "text/plain") {
failed(`${f.name}非txt文件,请上传txt格式文件!`)
return false
}
setUploadLoading(true)
ipcRenderer.invoke("fetch-file-content", (f as any).path).then((res) => {
setParams({...params, Target: res})
setTimeout(() => setUploadLoading(false), 100)
})
return false
}}
item={{
style: {textAlign: "left"},
label: "检测的目标",
}}
textarea={{
isBubbing: true,
setValue: (Target) => setParams({...params, Target}),
value: params.Target,
rows: 1,
placeholder: "可接受输入为:URL / IP / 域名 / 主机:端口,逗号分隔"
}}
suffixNode={
executing ? (
<Popconfirm
title={"确定要停止该漏洞检测?"}
onConfirm={(e) => ipcRenderer.invoke("cancel-exec-batch-yak-script", token)}
>
<Button type='primary' danger>
强制停止
</Button>
</Popconfirm>
) : (
<Button type='primary' htmlType='submit'>
开始检测
</Button>
)
}
></ContentUploadInput>
</Spin>
<div style={{width: "100%", textAlign: "left", paddingLeft: 84}}>
<Space>
<Tag>并发/线程: {params.Concurrent}</Tag>
<Tag>总超时: {params.TotalTimeoutSeconds} sec</Tag>
<Button
type={"link"}
style={{margin: 0, paddingLeft: 0}}
onClick={(e) => {
showModal({
title: "设置批量检测额外参数",
content: (
<>
<Form
onSubmitCapture={(e) => e.preventDefault()}
labelCol={{span: 7}}
wrapperCol={{span: 14}}
>
<InputInteger
label={"并发量(线程)"}
setValue={(Concurrent) =>
setParams({...params, Concurrent})
}
defaultValue={params.Concurrent}
/>
<InputInteger
label={"总超时时间/s"}
setValue={(TotalTimeoutSeconds) =>
setParams({
...params,
TotalTimeoutSeconds
})
}
defaultValue={params.TotalTimeoutSeconds}
/>
</Form>
</>
)
})
}}
>
额外参数
</Button>
</Space>
</div>
</Space>
</Form>
</Col>
<Col span={3} style={{position: "relative"}}>
<div style={{width: 140, position: "absolute", right: 2, bottom: 2}}>
<span style={{display: "inline-block", height: 22, marginRight: 5}}>只展示命中项</span>
<Switch checked={checked} onChange={(checked) => setChecked(checked)}></Switch>
</div>
</Col>
</Row>
<Divider style={{margin: "10px 0"}} />
<div ref={listRef} className='bug-test-list'>
{tasks.length === 0 ? (
<div>
<Empty
style={{marginTop: 75}}
description={"模块还未加载,请点击右上角配置进行插件仓库更新"}
></Empty>
</div>
) : checked ? (
<div ref={filterContainerRef} style={{height: listHeight, overflow: "auto"}}>
<div ref={filterWrapperRef}>
{filterList.map((ele) => (
<div className='list-item' key={ele.data.Id}>
<Text ellipsis={{tooltip: true}} copyable={true} style={{width: 260}}>
{ele.data.Id}
</Text>
<Divider type='vertical' />
<div style={{width: 120, textAlign: "center"}}>
{StatusToVerboseTag(ele.data.Status)}
</div>
<Divider type='vertical' />
<div>
<ExecResultsViewer results={ele.data.Results} oneLine={true} />
</div>
<Divider type='vertical' />
<div style={{flexGrow: 1, textAlign: "right"}}>
<Space>
<Button
type={"primary"}
size={"small"}
onClick={(e) => {
if (!ele.data.PoC) {
Modal.error({title: "没有模块信息"})
return
}
showModal({
title: `单体模块测试: ${ele.data.PoC.ScriptName}`,
width: "75%",
content: (
<>
<YakScriptOperator script={ele.data.PoC} target={params.Target} />
</>
)
})
}}
>
复测
</Button>
<Button
size={"small"}
style={{marginRight: 8}}
onClick={(e) => {
if (!ele.data.PoC) {
Modal.error({title: "没有模块信息"})
return
}
showModal({
title: `源码: ${ele.data.PoC.ScriptName}`,
width: "75%",
content: (
<>
<div style={{height: 400}}>
<YakEditor
readOnly={true}
type={"yaml"}
value={ele.data.PoC.Content}
/>
</div>
</>
)
})
}}
>
源码
</Button>
</Space>
</div>
</div>
))}
</div>
</div>
) : (
<div ref={containerRef} style={{height: listHeight, overflow: "auto"}}>
<div ref={wrapperRef}>
{list.map((ele) => (
<div className='list-item' key={ele.data.Id}>
<Text ellipsis={{tooltip: true}} copyable={true} style={{width: 260}}>
{ele.data.Id}
</Text>
<Divider type='vertical' />
<div style={{width: 120, textAlign: "center"}}>
{StatusToVerboseTag(ele.data.Status)}
</div>
<Divider type='vertical' />
<div>
<ExecResultsViewer results={ele.data.Results} oneLine={true} />
</div>
<Divider type='vertical' />
<div style={{flexGrow: 1, textAlign: "right"}}>
<Space>
<Button
type={"primary"}
size={"small"}
onClick={(e) => {
if (!ele.data.PoC) {
Modal.error({title: "没有模块信息"})
return
}
showModal({
title: `单体模块测试: ${ele.data.PoC.ScriptName}`,
width: "75%",
content: (
<>
<YakScriptOperator script={ele.data.PoC} target={params.Target} />
</>
)
})
}}
>
复测
</Button>
<Button
size={"small"}
style={{marginRight: 8}}
onClick={(e) => {
if (!ele.data.PoC) {
Modal.error({title: "没有模块信息"})
return
}
showModal({
title: `源码: ${ele.data.PoC.ScriptName}`,
width: "75%",
content: (
<>
<div style={{height: 400}}>
<YakEditor
readOnly={true}
type={"yaml"}
value={ele.data.PoC.Content}
/>
</div>
</>
)
})
}}
>
源码
</Button>
</Space>
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>
)
}