简体   繁体   English

用 API 调用更新父 state 然后更新子

[英]React Updating parent state with API call and then update child

I want my child to rerender when my parent updates its state.当我的父母更新其 state 时,我希望我的孩子重新渲染。 Seems simple but I haven't gotten it to work.看起来很简单,但我还没有让它工作。

In App.js i make the API call in componentWillMount.在 App.js 中,我在 componentWillMount 中调用 API。 I then want "PrivateRoute" to update the state "auth" but it seems like componentDidUpdate never runs and I always get rediercted.然后我希望“PrivateRoute”更新 state“auth”,但似乎 componentDidUpdate 从未运行,我总是被重定向。

The purpose of the code is that the API call checks if the user has a valid authentication token and then sets the "isLoggedIn" state to true or false.代码的目的是 API 调用检查用户是否具有有效的身份验证令牌,然后将“isLoggedIn”state 设置为 true 或 false。 This should make the child "PrivateRoute" either redirect (if isLoggedIn is false) or render another page (if isLoggedIn is true).这应该使子“PrivateRoute”重定向(如果 isLoggedIn 为假)或呈现另一个页面(如果 isLoggedIn 为真)。

I have checked out a lot of other similar questions but no solution has worked this far.我检查了很多其他类似的问题,但到目前为止还没有解决方案。

My app.js:我的 app.js:

import React, { Component } from "react";

import {
  BrowserRouter as Router,
  Route,
  Switch,
  Link,
  Redirect,
} from "react-router-dom";

import axios from "axios";

import PrivateRoute from "./components/PrivateRoute";

// Pages
import IndexPage from "./pages/index";
import HomePage from "./pages/home";

class App extends Component {
  constructor() {
    super();
    console.log("Constructor");
    this.state = {
      loggedInStatus: false,
      test: "TEST",
    };
  }

  // Checks if user is logged in
  checkAuth() {
    let token = localStorage.getItem("token");
    let isLoggedIn = false;
    if (token === null) token = "bad";

    console.log("Making API call");
    // API call
    axios
      .get("http://localhost:8000/authentication/checkAuth", {
        headers: { Authorization: "token " + token },
      })
      .then((res) => {
        console.log("Updateing state");
        this.setState({ loggedInStatus: true });
      })
      .catch((error) => {
        console.log("Updating state");
        this.setState({ loggedInStatus: false });
      });
    return isLoggedIn;
  }

  componentWillMount() {
    this.checkAuth();
  }

  render() {
    //console.log("Render");
    // console.log("isLoggedIn: ", this.state.loggedInStatus);

    return (
      <Router>
        <Switch>
          <PrivateRoute
            exact
            path="/home"
            component={HomePage}
            auth={this.state.loggedInStatus}
          />
          <Route exact path="/" component={IndexPage} />
        </Switch>
      </Router>
    );
  }
}

export default App;

PrivateRoute.jsx: PrivateRoute.jsx:

import { Redirect } from "react-router-dom";
import React, { Component } from "react";

class PrivateRoute extends Component {
  state = {};

  constructor(props) {
    super(props);
    this.state.auth = false;
  }

  // Update child if parent state is updated
  componentDidUpdate(prevProps) {
    console.log("Component did update");
    if (this.props.auth !== prevProps.auth) {
      console.log("Child component update");
      this.setState({ auth: this.props.auth ? true : false });
    }
  }

  render() {
    console.log("Props: ", this.props);
    console.log("State: ", this.state);
    //alert("this.props.auth: ", this.props.auth);
    //alert("TEST: ", this.props.test);
    if (this.props.auth) {
      return <h1>Success!</h1>;
      //return <Component {...this.props} />;
    } else {
      return (
        <Redirect
          to={{ pathname: "/", state: { from: this.props.location } }}
        />
      );
    }
  }
}

export default PrivateRoute;

checkAuth should be sync, if you want auth status before first-ever render in the component. checkAuth 应该是同步的,如果你想在组件中首次渲染之前获得身份验证状态。

Your checkAuth will return instantly, making the auth status always false.您的 checkAuth 将立即返回,使身份验证状态始终为假。

async checkAuth() {
    try {
        let token = localStorage.getItem("token");
        let isLoggedIn = false;
        if (token === null) token = "bad";
        const res = await axios
            .get("http://localhost:8000/authentication/checkAuth", {
                headers: {Authorization: "token " + token},
            })
        console.log("Updateing state");
        this.setState({loggedInStatus: true});
    } catch (e) {
        // for non 2XX axios will throw error
        console.log("Updating state");
        this.setState({loggedInStatus: false});
    }
}

async componentWillMount() {
    await this.checkAuth();
  }

In the child component, you have to set state from props.在子组件中,您必须从道具中设置 state。

constructor(props) {
    super(props);
    this.state.auth = props.auth;
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM