首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >useState set方法不能立即反映更改

useState set方法不能立即反映更改
EN

Stack Overflow用户
提问于 2019-01-07 14:05:33
回答 4查看 378.3K关注 0票数 487

我正在尝试学习钩子和useState方法把我搞糊涂了。我以数组的形式将初始值赋给状态。中的set方法useState对我来说是不起作用的,即使是spread(...)或者without spread operator..。我在另一台PC上创建了一个API,我正在调用该API并获取我想要设置到状态中的数据。

下面是我的代码:

代码语言:javascript
复制
// 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 hello;
};

const rootElement = document.getElementById("root");
ReactDOM.render(, rootElement);

​The setMovies(result)以及setMovies(...result)不起作用。这里需要一些帮助。

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-01-07 14:15:28

与通过扩展创建的类组件中的setState非常相似React.Component或者React.PureComponent提供的更新程序进行状态更新。useState钩子也是异步的,不会立即反映出来。

此外,这里的主要问题不仅仅是异步性质,还有一个事实,即函数根据其当前闭包使用状态值,状态更新将反映在下一次重新呈现中,现有的闭包不会受到影响,但会创建新的闭包..。现在,在当前状态下,钩子中的值由现有的闭包获得,当重新呈现发生时,闭包将根据是否重新创建函数来更新。

即使您添加了一个setTimeout虽然超时将在重新呈现发生的一段时间后运行,但setTimeout仍将使用前一个闭包中的值,而不是更新后的值。

代码语言:javascript
复制
setMovies(result);
console.log(movies) // movies here will not be updated

如果希望在状态更新时执行操作,则需要使用useEffect挂钩,这与使用componentDidUpdate在类组件中,因为useState返回的setter没有回调模式

代码语言:javascript
复制
useEffect(() => {
    // action on update of movies
}, [movies]);

就更新状态的语法而言,setMovies(result)将替换以前的movies

状态中的值与异步请求中可用的值。但是,如果要将响应与以前存在的值合并,则必须使用状态更新的回调语法,并正确使用扩展语法,如

代码语言:javascript
复制
setMovies(prevMovies => ([...prevMovies, ...result]));
票数 589
EN

Stack Overflow用户

发布于 2020-12-24 17:28:16

您可以通过使用useRef钩子,但当它更新时,它将不会重新渲染.我已经创建了一个名为useStateRef的钩子,它为您提供了来自两个世界的好处。这就像一种状态,当它被更新时,组件会重新呈现,它就像一个总是具有最新值的"ref“。

请参阅此示例:

代码语言:javascript
复制
var [state,setState,ref]=useStateRef(0)

它的工作原理与useState但除此之外,它还为您提供了以下内容的当前状态:ref.current

了解更多信息:

票数 12
EN

Stack Overflow用户

发布于 2020-06-17 01:02:52

我刚刚用useReducer完成了一次重写,遵循了@kentcdobs的文章(参考下文),这篇文章确实给了我一个可靠的结果,没有受到这些闭包问题的影响。

请参见:https://kentcdodds.com/blog/how-to-use-react-context-effectively

我将他的可读样板压缩为我喜欢的DRYness级别--阅读他的沙箱实现将向您展示它是如何实际工作的。

享受吧,我知道我是!!

代码语言:javascript
复制
import React from 'react'

// ref: https://kentcdodds.com/blog/how-to-use-react-context-effectively

const ApplicationDispatch = React.createContext()
const ApplicationContext = React.createContext()

function stateReducer(state, action) {
  if (state.hasOwnProperty(action.type)) {
    return { ...state, [action.type]: state[action.type] = action.newValue };
  }
  throw new Error(`Unhandled action type: ${action.type}`);
}

const initialState = {
  keyCode: '',
  testCode: '',
  testMode: false,
  phoneNumber: '',
  resultCode: null,
  mobileInfo: '',
  configName: '',
  appConfig: {},
};

function DispatchProvider({ children }) {
  const [state, dispatch] = React.useReducer(stateReducer, initialState);
  return (
    
      
        {children}
      
    
  )
}

function useDispatchable(stateName) {
  const context = React.useContext(ApplicationContext);
  const dispatch = React.useContext(ApplicationDispatch);
  return [context[stateName], newValue => dispatch({ type: stateName, newValue })];
}

function useKeyCode() { return useDispatchable('keyCode'); }
function useTestCode() { return useDispatchable('testCode'); }
function useTestMode() { return useDispatchable('testMode'); }
function usePhoneNumber() { return useDispatchable('phoneNumber'); }
function useResultCode() { return useDispatchable('resultCode'); }
function useMobileInfo() { return useDispatchable('mobileInfo'); }
function useConfigName() { return useDispatchable('configName'); }
function useAppConfig() { return useDispatchable('appConfig'); }

export {
  DispatchProvider,
  useKeyCode,
  useTestCode,
  useTestMode,
  usePhoneNumber,
  useResultCode,
  useMobileInfo,
  useConfigName,
  useAppConfig,
}

用法类似于:

代码语言:javascript
复制
import { useHistory } from "react-router-dom";

// https://react-bootstrap.github.io/components/alerts
import { Container, Row } from 'react-bootstrap';

import { useAppConfig, useKeyCode, usePhoneNumber } from '../../ApplicationDispatchProvider';

import { ControlSet } from '../../components/control-set';
import { keypadClass } from '../../utils/style-utils';
import { MaskedEntry } from '../../components/masked-entry';
import { Messaging } from '../../components/messaging';
import { SimpleKeypad, HandleKeyPress, ALT_ID } from '../../components/simple-keypad';

export const AltIdPage = () => {
  const history = useHistory();
  const [keyCode, setKeyCode] = useKeyCode();
  const [phoneNumber, setPhoneNumber] = usePhoneNumber();
  const [appConfig, setAppConfig] = useAppConfig();

  const keyPressed = btn => {
    const maxLen = appConfig.phoneNumberEntry.entryLen;
    const newValue = HandleKeyPress(btn, phoneNumber).slice(0, maxLen);
    setPhoneNumber(newValue);
  }

  const doSubmit = () => {
    history.push('s');
  }

  const disableBtns = phoneNumber.length < appConfig.phoneNumberEntry.entryLen;

  return (
    
      
        
      
      
        
      
      
        
      
      
        
      
    
  );
};

AltIdPage.propTypes = {};

现在,我的所有页面上的所有内容都很流畅

很好!

谢谢Kent!

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54069253

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档