useContext不能在初始请求时从上下文提供者获取更新值

时间:2020-05-20 19:56:24

标签: javascript reactjs react-router react-hooks react-context

这是我的身份验证上下文

import { createContext } from "react";
const AuthContext = createContext();
export default AuthContext;

这是我的身份验证器

import { AUTH_ERROR, LOGIN_SUCCESS } from "../types";
export default (state, action) => {
switch (action.type) {
case LOGIN_SUCCESS:
  localStorage.setItem("token", action.payload.data.token);
  return {
    ...state,
    isAuthenticated: true,
    userName: action.payload.data.name,
    avatar: action.payload.data.avatar,
    token: action.payload.data.token,
    error: null,
  };

  case AUTH_ERROR:
  localStorage.removeItem("token");
  return {
    ...state,
    isAuthenticated: false,
    userName: null,
    avatar: null,
    error: action.payload.message,
  };

default:
  return state;
}
};

这是我的身份验证状态

import React, { useReducer } from "react";
import axios from "axios";
import AuthContext from "./AuthContext";
import AuthReducer from "./AuthReducer";
import { AUTH_ERROR, LOGIN_SUCCESS } from "../types";

const AuthState = ({ children }) => {
const initialState = {
isAuthenticated: false,
userName: null,
avatar: null,
token: null,
error: null,
};

const [state, dispatch] = useReducer(AuthReducer, initialState);

const login = async (formData) => {
const header = {
  headers: {
    "Content-Type": "application/json",
  },
};

try {
  const res = await axios.post("/api/tenant/auth/login", formData, header);
  dispatch({
    type: LOGIN_SUCCESS,
    payload: res.data,
  });
} catch (err) {
  dispatch({
    type: AUTH_ERROR,
    payload: err.response.data,
   });
  }
 };

 return (
 <AuthContext.Provider
  value={{
    token: state.token,
    isAuthenticated: state.isAuthenticated,
    userName: state.userName,
    avatar: state.avatar,
    error: state.error,
    login,
  }}
  >
   {children}
 </AuthContext.Provider>
 );
};

 export default AuthState;

在我的app.js中,我包裹了这样的组件;

function App() {
return (
<AuthState>
  <AlertState>
    <SettingsState>
      <Alert />
      <Router>
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/login" exact component={Login} />
          <Route path="/dashboard" exact component={Dashboard} />
          <Route path="/main-settings" exact component={MainSettings} />
        </Switch>
      </Router>
    </SettingsState>
  </AlertState>
</AuthState>
);
}

然后在登录组件中,我试图像这样使用auth上下文提供程序中的数据;

const Login = ({ history }) => {
const { login, error, userName, isAuthenticated } = useContext(AuthContext);
const { setAlert } = useContext(AlertContext);

return (
 <Formik
  initialValues={{ email: "", password: "" }}
  validationSchema={Yup.object({
    email: Yup.string().email("Invalid email address").required("Required"),
    password: Yup.string().required("Required"),
  })}
  onSubmit={async (values, { resetForm, setSubmitting }) => {
    const { email, password } = values;
    await login({
      email,
      password,
    });
    console.log(error, userName, isAuthenticated);
   }}
  >
  {(formik) => (
    <>
      <div className="container">
        <div className="row justify-content-center">
          <div className="col-md-8 col-lg-6 col-xl-5">
            <div className="card mt-5 shadow">
              <div className="card-body p-4" id="error-body">
                <div className="text-center mb-4">
                  <h4 className="text-uppercase mt-0">Sign In</h4>
                </div>
                <form id="login-form" onSubmit={formik.handleSubmit}>
                  <div className="form-group">
                    <label htmlFor="email" className="float-left">
                      Email <span className="text-danger">*</span>
                    </label>
                    <input
                      type="text"
                      className="form-control"
                      id="email"
                      placeholder=""
                      name="email"
                      onChange={formik.handleChange}
                      onBlur={formik.handleBlur}
                      value={formik.values.email}
                    />
                    {formik.touched.email && formik.errors.email ? (
                      <div className="text-danger">
                        {formik.errors.email}
                      </div>
                    ) : null}
                  </div>
                  <div className="form-group">
                    <label htmlFor="password" className="float-left">
                      Password <span className="text-danger">*</span>
                    </label>
                    <input
                      type="password"
                      className="form-control"
                      id="password"
                      placeholder="Password"
                      name="password"
                      onChange={formik.handleChange}
                      onBlur={formik.handleBlur}
                      value={formik.values.password}
                    />
                    {formik.touched.password && formik.errors.password ? (
                      <div className="text-danger">
                        {formik.errors.password}
                      </div>
                    ) : null}
                  </div>
                  <div className="form-group">
                    <button
                      className="btn btn-primary btn-block"
                      type="submit"
                      style={{
                        backgroundColor: "#007bff",
                        borderColor: "#007bff",
                      }}
                    >
                      Log In
                    </button>
                  </div>
                  <hr />
                  <div className="form-group mb-3 d-flex justify-content-between">
                    <div className="custom-control custom-checkbox">
                      <input
                        type="checkbox"
                        className="custom-control-input"
                        id="rememberMe"
                        value="remember"
                      />
                      <label
                        className="custom-control-label"
                        htmlFor="rememberMe"
                      >
                        Remember Me
                      </label>
                    </div>
                    <h6>Forgot Password?</h6>
                  </div>
                </form>
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  )}
</Formik>
);
};

提交后,我签入开发人员工具,并且看到上下文提供程序已更新,但是每当我使用useContext访问数据时,都会从控制台获取处于状态的初始数据。我认为在发出初始请求并更新状态后,我的组件没有被重新渲染。因此,在我获得更新值的后续请求中。我在做什么错,因此我如何在第一次请求时获得更新的值?

1 个答案:

答案 0 :(得分:0)

尝试将console.log(error, userName, isAuthenticated);从onSubmit函数中移出并将其放在以下行:const { setAlert } = useContext(AlertContext);下,您现在看到更新的上下文值了吗?