REACT-useContext状态共享同步问题

时间:2020-07-02 14:52:56

标签: reactjs react-native react-redux react-router

目标:-

我希望用户仅在登录后才能看到他/她的订单。因此,我正在使用AuthContext对登录数据和令牌的用户进行状态管理。

问题:-

当我将令牌从AuthContext传递到子组件时,AuthContext需要花费一些时间来验证后端的令牌,同时子组件的逻辑中断。

子组件(使用状态/令牌):

const MyOrders = () => {
    const { userData } = useContext(AuthContext);
    const history = useHistory();
    if (!userData.token) {      // This redirects the user back to the home page immediately
        history.push("/");      // because the token hasn't been passed yet when
                                // the component is loaded
    };
    const getOrders = async () => {
        const url = 'http://localhost:5000/api/orders';
        try {
            const res = await axios.get(url, {
                headers: {
                    'x-auth-token': userData.token
                }
            });
            console.log(res.data);
        } catch (err) {
            console.log(err.response);
        }
    };
    useEffect(() => {
        if (userData.token) getOrders();
    }, []);

解决(安全吗???)

const MyOrders = () => {
    const token = localStorage.getItem('auth-token');  // Use localStorage token directly instead of 
                                                    // validating the token first (from AuthContext)??
    const history = useHistory();
    if (!token) {      
        history.push("/");                                      
    };

    const getOrders = async () => {
        const url = 'http://localhost:5000/api/orders';
        try {
            const res = await axios.get(url, {
                headers: {
                    'x-auth-token': token
                }
            });
            console.log(res.data);
        } catch (err) {
            console.log(err.response);
        }
    };

    useEffect(() => {
        if (userData.token) getOrders();
    }, []);

父组件(AuthContext): // //如果有人需要

const AuthContextProvider = (props) => {
    const [userData, setUserData] = useState({
        token: undefined,
        user: undefined
    });
    //Need to check if user is logged in
    //every time the App is rendered
    useEffect(() => {
        const checkLoggedIn = async () => {
            const url = "http://localhost:5000/api/users/token";
            let token = localStorage.getItem("auth-token");
            //when user is not logged in
            if(token === null) {
                localStorage.setItem("auth-token", "");
                token = "";
            }
            //need to validate the token if it exists
            const tokenResponse = await axios.post(url, null, {
                headers: { "x-auth-token": token }
            });
            //if token is valid, collect user data 
            if(tokenResponse.data){
                console.log(tokenResponse);
                setUserData({
                    token,
                    user: tokenResponse.data,

                });
            } else {
                localStorage.setItem("auth-token", "");
                token = "";
            };
        };
        checkLoggedIn();                
    }, []);

3 个答案:

答案 0 :(得分:0)

也许您可以尝试在history.push(“ /”)之后尽早返回,以便其余逻辑不会执行

const MyOrders = () => {
    const { userData } = useContext(AuthContext);
    const history = useHistory();
    if (!userData.token) {      // This redirects the user back to the home page immediately
        history.push("/");  
        return (null)
    };
    const getOrders = async () => {
        const url = 'http://localhost:5000/api/orders';
        try {
            const res = await axios.get(url, {
                headers: {
                    'x-auth-token': userData.token
                }
            });
            console.log(res.data);
        } catch (err) {
            console.log(err.response);
        }
    };
    useEffect(() => {
        if (userData.token) getOrders();
    }, []);

答案 1 :(得分:0)

我为您提供尝试在应用程序第一页中检索保存的令牌的功能。 在功能上使用“等待”。尝试从localStorage检索完成后, 如果令牌不存在,则应导航至登录名,否则应导航至主页。 在这种情况下,如果您有令牌,就不会有未定义的令牌,

但是,如果令牌以某种方式未定义怎么办?如果用户尝试使用未定义的令牌进行获取,则需要从服务器发送未授权错误,然后在客户端捕获错误,检查消息和收到的类型,如果确实发生授权错误,请导航至首页页面。

这是一个有点复杂的答案,但它肯定可以解决您的问题,并且将使它变得更简洁和更简洁。

答案 2 :(得分:0)

您可以向用户数据中添加加载,如果设置用户数据失败,则将加载设置为false,您可以通过从react-router返回一个Redirect组件来按订单进行重定向。

const AuthContext = React.createContext();
const AuthContextProvider = ({ children }) => {
  const [userData, setUserData] = React.useState({
    token: undefined,
    user: undefined,
    loading: true,
  });
  React.useEffect(() => {
    setTimeout(
      () =>
        setUserData((userData) => ({
          ...userData, //any other data that may be there
          token: 123,
          user: 'Hello world',
          loading: false, //not loading anymore
        })),
      5000 //wait 5 seconds to set user data
    );
  }, []);
  return (
    <AuthContext.Provider value={userData}>
      {children}
    </AuthContext.Provider>
  );
};
const App = () => {
  const { loading, ...userData } = React.useContext(
    AuthContext
  );
  if (!loading && !userData.token) {
    //snippet does not have redirect
    //  but if you have react-router you
    //  can do this
    //return <Redirect to="/" />;
  }
  React.useEffect(() => {}, []);
  return loading ? (
    'loading...'
  ) : (
    <pre>{JSON.stringify(userData, undefined, 2)}</pre>
  );
};
ReactDOM.render(
  <AuthContextProvider>
    <App />
  </AuthContextProvider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

相关问题