反应 useState 总是给出以前的状态值

Posted

技术标签:

【中文标题】反应 useState 总是给出以前的状态值【英文标题】:React useState giving previous state value always 【发布时间】:2019-12-09 00:02:37 【问题描述】:

我是 React Hooks 的新手,正在尝试构建功能组件。在我的组件中,我有两个日历,用户可以选择日期范围。当用户选择日期时,我需要更新我的查询。我尝试使用 useState 但我的状态值总是被盗并且总是给我以前的日历值。我尝试了 useRef 没有任何成功。

import React, useState, useEffect, useRef from 'react';
import  makeStyles  from '@material-ui/core/styles';
import  createRefetchContainer, graphql  from "react-relay";
import MaterialTable, MTableToolbar from 'material-table';
import moment from 'moment';
import 
  Radio,
  RadioGroup,
  FormControlLabel  from '@material-ui/core';

 import MomentUtils from '@date-io/moment';
 import  DatePicker,MuiPickersUtilsProvider  from '@material-ui/pickers';

const useStyles = makeStyles(theme => (
  root: 
    flexGrow: 1,
    display: 'flex',
    flexWrap: 'wrap',
  ,
  control: 
    padding: theme.spacing(2),
  ,
  group: 
    margin: theme.spacing(0, 1),
  ,
));

let liveDate = (numberofDays) => 
 return 
    Logical_Operator: "AND",
    Rules: [
      Field:"startdate", Value: moment().format("MM/DD/YYYY"),
       Comparison_Operator: "GREATER_THAN_EQUAL", Type: "String",
      Field:"startdate", Value:moment().add(numberofDays,'days').format("MM/DD/YYYY"),   Comparison_Operator:"LESS_THAN_EQUAL", Type: "String",
      Field:"active", Value:"True",Comparison_Operator: "EQUAL", Type: "Boolean"
    ]
  


const UpcomingCampaigns = (props) => 
  const [sort] = useState(field: "startdate", direction:"Asc");
  const [value, setValue] = useState("0");
  const [startDate, setstartDate] = useState(moment().format("MM/DD/YYYY"));
  const [endDate, setendDate] = useState(moment().format("MM/DD/YYYY"));

  //https://overreacted.io/how-are-function-components-different-from-classes/
  const lateststartDate = useRef(startDate);
  const latestendDate = useRef(endDate);

  function handleChange(event) 

    setValue(event.target.value);
    props.relay.refetch(
      dynamic_query: liveDate(event.target.value),
      sort, null,
      () => console.log('Refetch done'),
      force:true);
  

  useEffect( () => 
    lateststartDate.current = startDate;
    latestendDate.current = endDate;
    props.relay.refetch(
      dynamic_query: liveDate(0),
      sort);
  , []);

  let ReRunQuery = () => 
    console.log('StartDate is ', moment(startDate).format("MM/DD/YYYY"))
    console.log('EndDate is ', moment(endDate).format("MM/DD/YYYY"))
    let newQuery = 
       Logical_Operator: "AND",
       Rules: [
         Field:"startdate", Value: startDate,
          Comparison_Operator: "GREATER_THAN_EQUAL", Type: "String",
         Field:"enddate", Value:endDate, Comparison_Operator:"LESS_THAN_EQUAL", Type: "String",
         Field:"active", Value:"True",Comparison_Operator: "EQUAL", Type: "Boolean"
       ]
     ;

     console.log('New Query is ', newQuery)
     props.relay.refetch(
      dynamic_query: newQuery,
      sort, null,
      () => console.log('Refetch done'),
      force:true);

   

  const handleStartDateChange = (date) => 
    setstartDate(moment(date).format("MM/DD/YYYY"));
    console.log('StartDate is ', startDate)
    console.log('latest StartDate is ', moment(lateststartDate.current).format("MM/DD/YYYY"))
    //ReRunQuery();
  
  const handleEndDateChange = (date) => 
    setendDate(moment(date).format("MM/DD/YYYY"));
    console.log('Again EndDate is ', moment(latestendDate.current).format("MM/DD/YYYY"))
    //ReRunQuery();
  

  const buildData = () => 
    let tabledata = [];

    props.Viewer &&
      props.Viewer.CampaignGrids &&
      props.Viewer.CampaignGrids.edges.length &&
      props.Viewer.CampaignGrids.edges.map(( node ) => 
        const flattenCampaign = (Campaign_TypeFull,...rest) => Object.assign(, rest, Campaign_TypeFull);
        tabledata.push(flattenCampaign(node))
      )
    
    return tabledata;
  

  const renderTable = () => 
    let campaignData = buildData();
    const classes = useStyles();

    return (
      <div>

        <MaterialTable
          columns=[
             title: 'Name', field: 'Name',
             title: 'Campaign Type', field: 'text',
             title: 'Start Date', field: 'Start_Date',
             title: 'End Date', field: 'End_Date',
          ]
          data=campaignData
          title="Upcoming Active Campaigns"
          options=
               paging:false,
                search: false,
                //totalCount: props.Viewer.Campaigns.totalCount,
                backgroundColor: '#EEE',
                headerStyle:  backgroundColor: '#039be5', color: '#FFF', 'fontWeight': 'bold', 'fontSize' : '14px',
                rowStyle: backgroundColor: '#EEE',
                doubleHorizontalScroll: true,
                maxBodyHeight:225,
                paginationType: 'normal',
                emptyRowsWhenPaging: false,
              
          components=
            Toolbar: props => (
              <div>
                  <MTableToolbar ...props />
                  <RadioGroup
                      aria-label="Gender"
                      name="gender1"
                      className=classes.group
                      value=value
                      row=true
                      onChange=handleChange
                    >
                    <FormControlLabel value="0" control=<Radio /> label="Today" />
                    /* <FormControlLabel value="3" control=<Radio /> label="Next 3 days" />
                    <FormControlLabel value="7" control=<Radio /> label="Next 7 days" /> */
                    <DatePicker value=startDate label="Start Date" onChange=date => handleStartDateChange(date) autoOk="true" format="MM/DD/YYYY" variant="inline"
                    inputVariant="outlined" />
                    <DatePicker value=endDate label="End Date" onChange= date => handleEndDateChange(date) autoOk="true" format="MM/DD/YYYY" variant="inline"
                    inputVariant="outlined" />

                    </RadioGroup>
              </div>
            )
          
        />
      </div>
    )
  

  return (
    <MuiPickersUtilsProvider utils=MomentUtils>
      renderTable()
    </MuiPickersUtilsProvider>
  )


export default createRefetchContainer(
  UpcomingCampaigns,
  
    Viewer: graphql`
    fragment UpcomingCampaigns_Viewer on Viewer  @argumentDefinitions(
      sort: type: "Sort", defaultValue:field: "startdate", direction:"Asc"
      dynamic_query: 
        type: "QueryBuilder",
        defaultValue: 
          Logical_Operator:AND,
          Rules: [
            Field:"startdate", Value: "2019-04-28 23:59:59.000Z",Comparison_Operator:GREATER_THAN_EQUAL, Type: "String",
            Field:"startdate", Value:"2019-04-28 23:59:59.000Z",Comparison_Operator:LESS_THAN_EQUAL, Type: "String",
            Field:"active", Value:"True",Comparison_Operator:EQUAL, Type: "Boolean"
          ]
        
      
      ) 
      CampaignGrids(sort: $sort, dynamic_query:$dynamic_query ) 
        totalCount
        edges 
          node 
            id
            Name
            Campaign_Type
            Start_Date
            End_Date
            Campaign_TypeFull 
              text
              value
            

          
        
      
    
  `
,
graphql`
  query UpcomingCampaignsRefetchQuery(
    $dynamic_query: QueryBuilder!
    $sort: Sort
  ) 
    Viewer 
      ...UpcomingCampaigns_Viewer
      @arguments(
        dynamic_query: $dynamic_query
        sort: $sort
      )
    
  
`
);

我不确定我在这里缺少什么

【问题讨论】:

【参考方案1】:

如果你的 state 经常变化,转换成带 state 的 class 组件可以解决我们的问题。

【讨论】:

虽然我知道要提供帮助,但有效地声明“放弃并使用旧格式”在这里并不是特别有用! :)【参考方案2】:

useState 是异步的,因此有时该值不会立即生效 - 您需要实现 useEffect 才能使其正常运行

useEffect(() => 
 // do something when startDate updates
 , [startDate]);

【讨论】:

我已经有 useEffect 并且我添加了 [startDate] 但没有成功

以上是关于反应 useState 总是给出以前的状态值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用我的反应应用程序中的 useState 钩子给出的 setState 方法增加状态对象的选定索引的计数

如何在反应中使用带有useState钩子的回调[重复]

useState 与数组给出奇怪的结果

React Hooks useState+useEffect+event 给出过时的状态

在 useState 钩子中反应设置状态

为啥在反应的“useState”钩子中一遍又一遍地设置初始状态