reactjs 未保存上下文提供程序中更改的状态

mrphzbgm  于 2023-01-02  发布在  React
关注(0)|答案(1)|浏览(136)

因此我尝试将应用中一些与警报相关的逻辑集中在一个.tsx文件中,该文件需要在许多组件中可用(具体来说,是一个将从许多组件调用的“add alert”函数)。为此,我尝试使用react context使警报逻辑可用,状态(活动警报的数组)存储在App. tsx中。
Alerts.tsx

export interface AlertContext {
    alerts: Array<AppAlert>,
    addAlert: (msg: React.ReactNode, style: string, callback?: (id: string) => {}) => void,
    clearAlert: (id: string) => void
}
[...]
export function AlertsProvider(props: AlertsProps) {

    function clearAlert(id: string){
        let timeout = props.currentAlerts.find(t => t.id === id)?.timeout;
        if(timeout){
            clearTimeout(timeout);
        }

        let newCurrent = props.currentAlerts.filter(t => t.id != id);
        props.setCurrentAlerts(newCurrent);
    }

    function addAlert(msg: JSX.Element, style: string, callback: (id: string) => {}) {
        console.log("add alert triggered");
        let id = uuidv4();
        let newTimeout = setTimeout(clearAlert, timeoutMilliseconds, id);
        let newAlert = {
            id: id,
            msg: msg,
            style: style,
            callback: callback,
            timeout: newTimeout
        } as AppAlert;
        let test = [...props.currentAlerts, newAlert];
        console.log(test);
        props.setCurrentAlerts(test);
        console.log("current alerts", props.currentAlerts);
    }

    let test = {
        alerts: props.currentAlerts,
        addAlert: addAlert,
        clearAlert: clearAlert
    } as AlertContext;

    return (<AlertsContext.Provider value={test}>
        { props.children }
    </AlertsContext.Provider>);
}

App.tsx

function App(props: AppProps){
[...]
    const [currentAlerts, setCurrentAlerts] = useState<Array<AppAlert>>([]);
[...]
    const alertsContext = useContext(AlertsContext);

    console.log("render app", alertsContext.alerts);
    return (
      <AlertsProvider currentAlerts={currentAlerts} setCurrentAlerts={setCurrentAlerts}>
          <div className={ "app-container " + (error !== undefined ? "err" : "") } >
              { selectedMode === "Current" &&
                <CurrentItems {...currentItemsProps} />
              }
              { selectedMode === "History" &&
                <History {...historyProps } />
              }
              { selectedMode === "Configure" &&
                <Configure {...globalProps} />
              }
          </div>
          <div className="footer-container">
              {
                alertsContext.alerts.map(a => (
                  <Alert variant={a.style} dismissible transition={false} onClose={a.callback}>
                    {a.msg}
                  </Alert>
                ))
              }
              {/*<Alert variant="danger" dismissible transition={false}
                  show={ error !== undefined }
                  onClose={ dismissErrorAlert }>
                  <span>{ error?.msg }</span>
            </Alert>*/}
          </div>
      </AlertsProvider>
    );
}

export default App;

到目前为止,我只在CurrentItems.tsx中的一个地方调用alertsContext.addAlert。我还添加了一些控制台语句,以便于调试。控制台中的输出如下所示:

render app Array [] App.tsx:116
XHRGEThttp://localhost:49153/currentitems?view=Error [HTTP/1.1 500 Internal Server Error 1ms]
Error 500 fetching current items for view Error: Internal Server Error CurrentItems.tsx:94
add alert triggered Alerts.tsx:42
Array [ {…}, {…} ] Alerts.tsx:53
current alerts Array [ {…} ] Alerts.tsx:55
render app Array []

因此,我可以看到,在addAlert函数结束时,currentAlerts属性似乎已经更新,但随后App.tsx中的控制台语句显示它为空。我对React相对较新,因此我可能对如何使用/ function有一些误解,但我已经断断续续地戳了一天的大部分时间,但没有成功。所以我希望有人能纠正我。

carvr3hs

carvr3hs1#

const alertsContext = useContext(AlertsContext);

App中的这一行将在组件树中寻找一个位于 * 更高 * 位置的提供者。在App的 * 内部 * 有一个提供者,但这并不重要。由于组件树中没有位于更高位置的提供者,因此App将获得默认值,该值永远不会改变。
您需要颠倒组件的顺序,使提供者高于试图Map值的组件,或者由于状态变量已经在App中,您可以直接使用它并删除对useContext的调用:

function App(props: AppProps){
[...]
    const [currentAlerts, setCurrentAlerts] = useState<Array<AppAlert>>([]);
[...]
    // Delete this line
    // const alertsContext = useContext(AlertsContext);

    console.log("render app", currentAlerts);
[...]
    {
      currentAlerts.map(a => (
        <Alert variant={a.style} dismissible transition={false} onClose={a.callback}>
          {a.msg}
        </Alert>
      ))
    }
}

相关问题