我正在尝试学习钩子和useState方法使我困惑。我以数组的形式将初始值赋给一个状态。useState中的set方法不适合我,无论是否使用扩展语法。

我已经在另一台PC上做了一个API,我正在调用并获取我想设置为状态的数据。

这是我的代码:

<div id="root"></div> <script type="text/babel" defer> // import React, { useState, useEffect } from "react"; // import ReactDOM from "react-dom"; const { useState, useEffect } = React; // web-browser variant const StateSelector = () => { const initialValue = [ { category: "", photo: "", description: "", id: 0, name: "", rating: 0 } ]; const [movies, setMovies] = useState(initialValue); useEffect(() => { (async function() { try { // const response = await fetch("http://192.168.1.164:5000/movies/display"); // const json = await response.json(); // const result = json.data.result; const result = [ { category: "cat1", description: "desc1", id: "1546514491119", name: "randomname2", photo: null, rating: "3" }, { category: "cat2", description: "desc1", id: "1546837819818", name: "randomname1", rating: "5" } ]; console.log("result =", result); setMovies(result); console.log("movies =", movies); } catch (e) { console.error(e); } })(); }, []); return <p>hello</p>; }; const rootElement = document.getElementById("root"); ReactDOM.render(<StateSelector />, rootElement); </script> <script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script> <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>

setMovies(result)和setMovies(…result)都不起作用。

我希望结果变量被推入movies数组。


当前回答

React的useEffect有自己的状态/生命周期。它与状态突变有关,直到效果被破坏才会更新状态。

只要在参数状态中传递一个参数或留下一个黑色数组,它就会完美地工作。

React.useEffect(() => {
    console.log("effect");
    (async () => {
        try {
            let result = await fetch("/query/countries");
            const res = await result.json();
            let result1 = await fetch("/query/projects");
            const res1 = await result1.json();
            let result11 = await fetch("/query/regions");
            const res11 = await result11.json();
            setData({
                countries: res,
                projects: res1,
                regions: res11
            });
        } catch {}
    })(data)
}, [setData])
# or use this
useEffect(() => {
    (async () => {
        try {
            await Promise.all([
                fetch("/query/countries").then((response) => response.json()),
                fetch("/query/projects").then((response) => response.json()),
                fetch("/query/regions").then((response) => response.json())
            ]).then(([country, project, region]) => {
                // console.log(country, project, region);
                setData({
                    countries: country,
                    projects: project,
                    regions: region
                });
            })
        } catch {
            console.log("data fetch error")
        }
    })()
}, [setData]);

或者,您可以尝试React. useref()在React钩子中进行即时更改。

const movies = React.useRef(null);
useEffect(() => {
movies.current='values';
console.log(movies.current)
}, [])

其他回答

var [state,setState]=useState(defaultValue)

useEffect(()=>{
   var updatedState
   setState(currentState=>{    // Do not change the state by get the updated state
      updateState=currentState
      return currentState
   })
   alert(updateState) // the current state.
})

关闭并不是唯一的原因。

基于useState的源代码(下面进行了简化)。在我看来,价值从来没有被立即分配。

当您调用setValue时,更新操作将被排队。在时间表生效后,只有当你到达下一个渲染时,这些更新操作才会应用到那个状态。

这意味着即使我们没有闭包问题,useState的react版本也不会马上给你新值。新的值直到下一次渲染才会存在。

  function useState(initialState) {
    let hook;
    ...

    let baseState = hook.memoizedState;
    if (hook.queue.pending) {
      let firstUpdate = hook.queue.pending.next;

      do {
        const action = firstUpdate.action;
        baseState = action(baseState);            // setValue HERE
        firstUpdate = firstUpdate.next;
      } while (firstUpdate !== hook.queue.pending);

      hook.queue.pending = null;
    }
    hook.memoizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)];
  }

function dispatchAction(queue, action) {
  const update = {
    action,
    next: null
  };
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

  isMount = false;
  workInProgressHook = fiber.memoizedState;
  schedule();
}

还有一篇文章以类似的方式解释了上面的内容,https://dev.to/adamklein/we-don-t-know-how-react-state-hook-works-1lp8

使用后台定时器库。它解决了我的问题。

const timeoutId = BackgroundTimer.setTimeout(() => {
    // This will be executed once after 1 seconds
    // even when the application is the background
    console.log('tac');
}, 1000);

React的useEffect有自己的状态/生命周期。它与状态突变有关,直到效果被破坏才会更新状态。

只要在参数状态中传递一个参数或留下一个黑色数组,它就会完美地工作。

React.useEffect(() => {
    console.log("effect");
    (async () => {
        try {
            let result = await fetch("/query/countries");
            const res = await result.json();
            let result1 = await fetch("/query/projects");
            const res1 = await result1.json();
            let result11 = await fetch("/query/regions");
            const res11 = await result11.json();
            setData({
                countries: res,
                projects: res1,
                regions: res11
            });
        } catch {}
    })(data)
}, [setData])
# or use this
useEffect(() => {
    (async () => {
        try {
            await Promise.all([
                fetch("/query/countries").then((response) => response.json()),
                fetch("/query/projects").then((response) => response.json()),
                fetch("/query/regions").then((response) => response.json())
            ]).then(([country, project, region]) => {
                // console.log(country, project, region);
                setData({
                    countries: country,
                    projects: project,
                    regions: region
                });
            })
        } catch {
            console.log("data fetch error")
        }
    })()
}, [setData]);

或者,您可以尝试React. useref()在React钩子中进行即时更改。

const movies = React.useRef(null);
useEffect(() => {
movies.current='values';
console.log(movies.current)
}, [])

我发现这很好。不将状态(方法1)定义为,例如,

const initialValue = 1;
const [state,setState] = useState(initialValue)

试试这个方法(方法2),

const [state = initialValue,setState] = useState()

这在没有使用useEffect的情况下解决了渲染问题,因为在这种情况下我们不关心它的内部闭包方法。

附注:如果你关心在任何用例中使用旧状态,那么useState和useEffect需要使用,因为它需要那种状态,所以在这种情况下接近1应使用。