useState取决于其他状态

时间:2019-11-26 02:40:25

标签: react-hooks

我有这个useSiren钩子,应该用传入的json自变量更新其状态,但事实并非如此。

在第一次调用时,json是一个空对象,因为尚未运行获取效果。 在第二个调用中,它也是一个空对象(通过loadingApp中设置为true触发) 并在第三个调用中填充有效数据。但是,未应用有效数据。状态保持其初始值。

我猜想必须以某种方式调用setSiren来更新它,因为初始状态只能设置一次。但是我该怎么做呢?谁应该给`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)

2 个答案:

答案 0 :(得分:1)

也许您想做的就是在for(int x = 0; x < 1920; x++) { for(int y = 0; y < 1080; y++) { Point thepoint= new Point(-1,-1); grayCode.getProjPixel(photosCam1, x, y, thepoint ); projPix.Add(thepoint); } } 参数更改时更新siren状态?您可以使用useEffect自动更新它。

json

答案 1 :(得分:0)

@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

的作者和维护者