为什么状态变量不能通过上下文变量更新?

时间:2021-02-26 06:11:15

标签: javascript reactjs

这是我的代码: 顶级组件(即RosterScheduler.js)的源代码如下:

import {Col,Container,Row} from 'react-bootstrap';
import {useEffect,useState} from 'react';
import CalendarUtility from '../../../utils/calendar/CalendarUtility';
import MonthPicker from '../../monthPicker/MonthPicker';
import Roster from '../../../utils/Roster';
import RosterSchedulerTable from '../../tables/rosterSchedulerTable/RosterSchedulerTable';
export default function RosterScheduler(props){
    const [rosterMonth,setRosterMonth]=useState(new Date());
    const[rosterSchedulerData,setRosterSchedulerData]=useState();
    let monthPickerMinDate=props.systemParam.monthPickerMinDate;
    //console.log(monthPickerMinDate);
    monthPickerMinDate=new Date(monthPickerMinDate.year,monthPickerMinDate.month-1,monthPickerMinDate.date);

    //console.log(props);
    //console.log(props.systemParam.monthSelectorMinDate);
    let updateMonth=(year,month)=>{
        //console.log("updateMonth="+year+","+month);
        let newDate=new Date();
        newDate.setFullYear(year);
        newDate.setMonth(month);
        setRosterMonth(newDate);
    }
    let systemParam=props.systemParam;
    useEffect(()=>{
        const getData = async () => {
            let calendarUtility=new CalendarUtility();
            let monthlyCalendar=calendarUtility.getMonthlyCalendar(rosterMonth.getFullYear(),rosterMonth.getMonth());
            let roster = new Roster();
            let rosterData = await roster.getRosterSchedulerList(rosterMonth.getFullYear(),rosterMonth.getMonth()+1);
            let activeShiftInfoList= await roster.getAllActiveShiftInfo();
            setRosterSchedulerData(
               {
                "activeShiftInfoList":activeShiftInfoList,
                "calendarUtility":calendarUtility,
                "monthlyCalendar":monthlyCalendar,
                "rosterData":rosterData,                
                "systemParam":systemParam
               }
            )
        }
        getData();    
    },[rosterMonth]);
    return (
        <div className="App p-1">
            <Container fluid={true} className="tableContainer">
                <Row>
                    <Col className="font-weight-bold text-center tableCaption" md={12} lg={12} sm={12} xl={12} xs={12}>
                        <u>Computer Operation Support Services Team Roster</u>
                    </Col>
                </Row>
                <Row>
                    <Col md={12} lg={12} sm={12} xl={12} xs={12}>
                        <MonthPicker 
                            minDate={monthPickerMinDate}
                            onSelect={updateMonth} />
                    </Col>
                </Row>           
                <Row>
                    <Col className="d-flex justify-content-center p-0" md={12} lg={12} sm={12} xl={12} xs={12}>
                        {rosterSchedulerData && <RosterSchedulerTable rosterSchedulerData={rosterSchedulerData}/>}
                    </Col>
                </Row>
            </Container>        
        </div>
    )    
}

RosterSchedulerTable.js 源码如下:

import {useState} from 'react';
import RosterWebContext from '../../../RosterWebContext';
import RosterSchedulerTableBody from './rosterSchedulerTableBody/RosterSchedulerTableBody';

export default function RosterSchedulerTable(props){
    
    const [hightLightCellIndex, setHightLightCellIndex] = useState(-1);
    const [rosterData,setRosterData]=useState(props.rosterSchedulerData.rosterData);

    let activeShiftInfoList=props.rosterSchedulerData.activeShiftInfoList;
    let calendarUtility=props.rosterSchedulerData.calendarUtility;
    let monthlyCalendar=props.rosterSchedulerData.monthlyCalendar;
    let systemParam=props.rosterSchedulerData.systemParam;
    
    let contextValue={
        activeShiftInfoList,
        calendarUtility,
        hightLightCellIndex,
        monthlyCalendar,
        rosterData,
        setHightLightCellIndex,
        setRosterData,
        systemParam    
    };
    
    return (
        <table id="rosterTable">
            <RosterWebContext.Provider value={contextValue}>
                <RosterSchedulerTableBody/>
            </RosterWebContext.Provider>
        </table>
    );
}

RosterSchedulerTableBody.js 源代码如下:

import {useContext,useEffect,useState} from 'react';
import RosterSchedulerRow from './RosterSchedulerRow';
import VacantShiftRow from './VacantShiftRow';
export default function RosterSchedulerTableBody(){
    let {rosterData} = useContext(RosterWebContext);
    let rowList = [];
    console.log("data:"+rosterData.rosterList[1].shiftList.length);
    
    return (
        <tbody>            
            {rowList}
        </tbody>
    );
}

这是 RosterWebContext.js 的内容:

import React from 'react'
const RosterWebContext = React.createContext({});
export default RosterWebContext

页面加载完毕后,rosterDataRosterSchedulerTableRosterSchedulerTableBody的内容相同, 但是,当用户从 MonthPicker 中选择月份时,rosterData 中的状态变量 RosterSchedulerTable 应该被更新,然后它应该更新 rosterDataRosterSchedulerTableBody 的内容,不幸的是,rosterDataRosterSchedulerTableBody 的内容没有更新。

因为 roster.getRosterSchedulerList 和 roster.getAllActiveShiftInfo 方法都是从服务器获取数据,所以我无法在 stackblitz 上演示这个问题。

你能告诉我如何解决这个问题吗?

2 个答案:

答案 0 :(得分:0)

useState(initialState) 对安装组件后后续渲染中 initialState 的变化不敏感,因此 rosterData 不会在 props.rosterSchedulerData.rosterData 发生变化时发生变化。

如果您希望状态反映对 rosterSchedulerData.rosterData 组件中 RosterScheduler 的更改,解决方案是再次 lift your state

答案 1 :(得分:0)

最后,我让它正常工作了。

RosterSchedulerTable.js 源码如下:

import {useState} from 'react';
import RosterWebContext from '../../../RosterWebContext';
import RosterSchedulerTableBody from './rosterSchedulerTableBody/RosterSchedulerTableBody';
import TableHeader from '../tableHeader/TableHeader';
export default function RosterSchedulerTable(props){
    
    const [hightLightCellIndex, setHightLightCellIndex] = useState(-1);
    let activeShiftInfoList=props.rosterSchedulerData.activeShiftInfoList;
    let calendarUtility=props.rosterSchedulerData.calendarUtility;
    let monthlyCalendar=props.rosterSchedulerData.monthlyCalendar;
    let rosterData=props.rosterSchedulerData.rosterData;
    let systemParam=props.rosterSchedulerData.systemParam;
    
    useEffect(()=>{
          setRosterData(props.rosterSchedulerData.rosterData);
    },[props.rosterSchedulerData.rosterData])

    let contextValue={
        activeShiftInfoList,
        calendarUtility,
        hightLightCellIndex,
        monthlyCalendar,
        rosterData,
        setHightLightCellIndex,
        systemParam    
    };
    return (
        <table id="rosterTable">
            <RosterWebContext.Provider value={contextValue}>
                <TableHeader noOfPrevDate={systemParam.noOfPrevDate}/>
                <RosterSchedulerTableBody/>
            </RosterWebContext.Provider>
        </table>
    );
}

RosterSchedulerTableBody.js 源码如下:

import {useContext,useEffect,useState} from 'react';
import PreferredShiftRow from './PreferredShiftRow';
import RosterSchedulerRow from './RosterSchedulerRow';
import RosterWebContext from '../../../../RosterWebContext';
import VacantShiftRow from './VacantShiftRow';
export default function RosterSchedulerTableBody(){
    const[rosterInfo,setRosterInfo]=useState();
    let {rosterData} = useContext(RosterWebContext);
    
    let rowList = [];
    console.log("info:"+rosterInfo.rosterList[1].shiftList.length);
    console.log("data:"+rosterData.rosterList[1].shiftList.length);
    return (
        <tbody>            
            {rowList}
        </tbody>
    );
}

帕特里克,谢谢