使用状态取决于其他状态



我有这个useSiren钩子,应该使用传入的json参数更新其状态,但它没有。

在第一次调用时,json是一个空对象,因为 fetch 效果尚未运行。 在第二次调用时,它也是一个空对象(由loadingApp中设置为 true 触发( 在第三次调用时,它充满了有效数据。但是,不会应用有效数据。状态保持其初始值。

我想必须以某种方式调用setSiren来更新它,因为初始状态只能设置一次。但是我该怎么做呢?谁应该称呼"塞壬"?

import { h, render } from 'https://unpkg.com/preact@latest?module';
import { useEffect, useState, useCallback } from 'https://unpkg.com/preact@latest/hooks/dist/hooks.module.js?module';
import htm from "https://unpkg.com/htm@latest/dist/htm.module.js?module";
const html = htm.bind(h);
function useFetch({
method = "GET",
autoFetch = true,
href,
body
}) {
const [loading, setLoading] = useState(false)
const [error, setError] = useState()
const [response, setResponse] = useState()
const [isCancelled, cancel] = useState()
const [json, setJson] = useState({})
const sendRequest = async payload => {
try {
setLoading(true)
setError(undefined)
const response = await fetch(href.replace("http://", "https://"), {
method
})
const json = await response.json()
if (!isCancelled) {
setJson(json)
setResponse(response)
}
return json
} catch (err) {
if (!isCancelled) {
setError(err)
}
throw err
} finally {
setLoading(false)
}
}
if (autoFetch) {
useEffect(() => {
sendRequest(body)
return () => cancel(true)
}, [])
}
return [{
loading,
response,
error,
json
}, 
sendRequest
]
}
function useSiren(json) {
const [{ entities = [], actions = [], links, title }, setSiren] = useState(json)
const state = (entities.find(entity => entity.class === "state")) || {}
return [
{
title,
state,
actions
},
setSiren
]
}
function Action(props) {
const [{ loading, error, json }, sendRequest] = useFetch({ autoFetch: false, href: props.href, method: props.method })
const requestAndUpdate = () => {
sendRequest().then(props.onRefresh)
}
return (
html`
<button disabled=${loading} onClick=${requestAndUpdate}>
${props.title}
</button>
`
)
}
function App() {
const [{ loading, json }, sendRequest] = useFetch({ href: "https://restlr.io/toggle/0" })
const [{ state, actions }, setSiren] = useSiren(json)
return (
html`<div>
<div>State: ${loading ? "Loading..." : (state.properties && state.properties.value)}</div>
${actions.map(action => html`<${Action} href=${action.href} title=${action.title || action.name} method=${action.method} onRefresh=${setSiren}/>`)}
<button disabled=${loading} onClick=${sendRequest}>
REFRESH
</button>
</div>
`
);
}
render(html`<${App}/>`, document.body)

也许您要做的是在json参数更改时更新siren状态?您可以使用 useEffect 自动更新它。

function useSiren(json) {
const [{ entities = [], actions = [], links, title }, setSiren] = useState(json)
useEffect(() => { // here
setSiren(json)
}, [json])
const state = (entities.find(entity => entity.class === "state")) || {}
return [
{
title,
state,
actions
},
setSiren
]
}

@awmleer提到的模式打包在use-selector

import { useSelectorValue } from 'use-selector';
const { entities=[], actions=[], title} = json;
const siren = useSelectorValue(() => ({
state: entities.find(entity => entity.class === 'state') || {},
actions,
title
}), [json]);

披露我是use-selector的作者和维护者

相关内容

  • 没有找到相关文章

最新更新