无法更改对象的状态

时间:2020-05-10 14:11:27

标签: reactjs axios fetch react-hooks use-state

我试图获取一个对象,并且获取,我在response.data中获取了正确的数据,但是我无法将其设置为state。它只是保留为空对象。我究竟做错了什么? Post是一个json对象,具有多个字段,例如:post_id,post_title,post_content等。

const [post, setPost] = useState({})

let id = match.params.id

useEffect(() => {
     axios.get(`${BASE_URL}/post?id=${id}`)
     .then(response => {
        console.log(response.data)
        setPost(response.data)
     })
     .then(() => {
            console.log("post: ", post)
        }
     )

3 个答案:

答案 0 :(得分:1)

像您的Text("abdominal pain") Text("abnormal menstruation") Text("acidity") Text("acute liver failure") Text("altered sensorium") Text("anxiety") 这样的

setAction是异步的,如官方REACT文档(https://reactjs.org/docs/hooks-reference.html#usestate)所述;这意味着,一旦执行了setAction,您就不会知道它何时会真正执行和终止:您将知道,因为组件将重新呈现。

在您的情况下,如果您想在setPost获得新值后执行操作,则需要使用post钩子(https://reactjs.org/docs/hooks-reference.html#useeffect):

useEffect

顺便说一句,我想您希望将数据保存在React.useEffect(() => { console.log(post); }, [post]); 中,因此您可能会保存从HTTP响应正文中检索到的JSON,您可以使用{{1} }。

编辑:如Siradji Awoual的评论所述,我写的关于responseresponse.json()的内容对Axios无效(但对于{{1 }} API)。

答案 1 :(得分:0)

设置状态是异步的。这意味着您不知道该动作何时完成执行。

如果我是你,我将使用诸如useEffect之类的方法来检查状态是否已设置。


React.useEffect(() => console.log(post), [post])

答案 2 :(得分:0)

使用axios.get是低级的,它要求您添加很多额外的内容才能正常工作。相反,请尝试编写自定义钩子以抽象该逻辑-

const identity = x => x

const useAsync = (runAsync = identity, deps = []) => {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const [result, setResult] = useState(null)

  useEffect(_ => { 
    Promise.resolve(runAsync(...deps))
      .then(setResult, setError)
      .finally(_ => setLoading(false))
  }, deps)

  return { loading, error, result }
}

使用useAsync看起来像这样-

const MyApp = () => {
  const { loading, error, result } =
    useAsync(_ => axios.get("./foo.json").then(res => res.json()))

  if (loading)
    return <p>loading...</p>

  if (error)
    return <p>error: {error.message}</p>

  return <pre>result: {result}</pre>
}

但是您可能会有许多获取JSON的组件,对吗?我们可以制作一个更高级别的自定义钩子useJSON,它是useAsync-

的特化
const fetchJson = (url = "") =>
  axios.get(url).then(r => r.json()) // <-- stop repeating yourself

const useJson = (url = "") =>
  useAsync(fetchJson, [url]) // <-- useAsync

const MyApp = () => {
  const { loading, error, result } =
    useJson("./foo.json")  // <-- dead simple

  if (loading)
    return <p>loading...</p>

  if (error)
    return <p>error: {error.message}</p>

  return <pre>result: {result}</pre>
}

请参见此功能代码段中的自定义钩子-

const { useState, useEffect } =
  React

// fake fetch slows response down so we can see loading
const _fetch = (url = "") =>
  fetch(url).then(x =>
    new Promise(r => setTimeout(r, 2000, x)))

const identity = x => x

const useAsync = (runAsync = identity, deps = []) => {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const [result, setResult] = useState(null)

  useEffect(_ => { 
    Promise.resolve(runAsync(...deps))
      .then(setResult, setError)
      .finally(_ => setLoading(false))
  }, deps)

  return { loading, error, result }
}

const fetchJson = (url = "") =>
  _fetch(url).then(r => r.json())

const useJson = (url = "") =>
  useAsync(fetchJson, [url])

const MyComponent = ({ url = "" }) => {
  const { loading, error, result } =
    useJson(url)

  if (loading)
    return <pre>loading...</pre>

  if (error)
    return <pre style={{color: "tomato"}}>error: {error.message}</pre>

  return <pre>result: {JSON.stringify(result, null, 2)}</pre>
}

const MyApp = () =>
  <main>
    ex 1 (success):
    <MyComponent url="https://httpbin.org/get?foo=bar" />

    ex 2 (error):
    <MyComponent url="https://httpbin.org/status/500" />
  </main>

ReactDOM.render(<MyApp />, document.body)
pre {
  background: ghostwhite;
  padding: 1rem;
  white-space: pre-wrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>