从零开始搭建群众权益平台(六)

本篇博客我们将继续完善处理错误,显示加载指示器,实现表单验证,处理跨域请求等。

错误处理:

在前端代码中,我们应当为所有网络请求添加错误处理逻辑。例如,如果后端返回了一个错误码,我们应当在前端捕获到这个错误,并向用户显示一个错误消息。

这里是一个简单的错误处理的例子:

async function handleSubmit(event) {
  event.preventDefault();
  try {
    const response = await axios.post('/api/login', { username, password });
    setToken(response.data.token);
  } catch (error) {
    console.error(error);
    if (error.response) {
      // 服务器返回了错误响应
      alert(`Login failed: ${error.response.data.message}`);
    } else {
      // 网络请求失败
      alert('Login failed: network error');
    }
  }
}

加载指示器:

如果一个操作需要花费一些时间来完成,例如网络请求,那么我们应该在这个操作进行期间显示一个加载指示器。

下面是如何在请求过程中显示一个加载指示器的例子:

function LoginPage() {
  const [loading, setLoading] = useState(false);
  // ...
  
  async function handleSubmit(event) {
    event.preventDefault();
    setLoading(true);
    try {
      const response = await axios.post('/api/login', { username, password });
      setToken(response.data.token);
    } catch (error) {
      // handle error...
    }
    setLoading(false);
  }
  
  return (
    <div>
      {loading ? <p>Loading...</p> : null}
      {/* other elements... */}
    </div>
  );
}

表单验证:

我们可以使用各种技术和库来实现表单验证,例如HTML5的内置验证功能,或者yupjoi等库。

这是一个使用HTML5内置验证功能的例子:

<form onSubmit={handleSubmit}>
  <input type="text" value={username} onChange={e => setUsername(e.target.value)} required />
  <input type="password" value={password} onChange={e => setPassword(e.target.value)} required minLength="8" />
  <button type="submit">Log in</button>
  {/* other elements... */}
</form>

跨域请求:

如果你的前端和后端部署在不同的域名下,你需要配置后端服务器来允许跨域请求。如果你的后端服务器是Express,你可以使用cors中间件来实现这个功能。

这是配置Express服务器允许所有跨域请求的代码

const cors = require('cors');
app.use(cors());

状态管理库:

如果你的应用的状态变得复杂,你可能需要引入一个状态管理库来帮助你管理状态。Redux和Vuex是两个流行的选择。

在Redux中,你创建一个或多个reducer来处理各种action,然后使用createStore函数来创建一个store。你可以使用store.dispatch来发送一个action,然后使用store.getState来获取当前的状态。你还可以使用react-redux库来连接你的React组件和Redux store。

在Redux中,创建一个简单的reducer和store的例子如下:

import { createStore } from 'redux';

function reducer(state = { token: null }, action) {
  switch (action.type) {
    case 'SET_TOKEN':
      return { ...state, token: action.payload };
    default:
      return state;
  }
}

const store = createStore(reducer);

然后你可以在你的组件中使用 react-redux 提供的 Providerconnect 函数来连接你的 React 组件和 Redux store。

import { Provider } from 'react-redux';
import { connect } from 'react-redux';

function LoginPage({ token, setToken }) {
  // ...
}

// 这个函数定义了如何将 Redux store 的状态映射到你的组件的 props
function mapStateToProps(state) {
  return { token: state.token };
}

// 这个函数定义了如何将 dispatch 函数映射到你的组件的 props
function mapDispatchToProps(dispatch) {
  return {
    setToken: token => dispatch({ type: 'SET_TOKEN', payload: token })
  };
}

// 使用 connect 函数连接你的组件和 Redux store
const ConnectedLoginPage = connect(mapStateToProps, mapDispatchToProps)(LoginPage);

// 在你的应用中使用 Provider 组件来提供 store
function App() {
  return (
    <Provider store={store}>
      <ConnectedLoginPage />
    </Provider>
  );
}

这只是 Redux 的基础使用。在实际的项目中,你可能还需要处理异步 action,组合多个 reducer,以及其他更复杂的用例。你可以查阅 Redux 的文档来了解更多信息。

Context 和 Hooks:

如果你不想使用状态管理库,或者你的项目不大到需要使用状态管理库,那么 Context 和 Hooks 是一个好的选择。在 React 中,你可以使用 Context 来在组件树中传递数据,而不需要通过每一层的 props 来手动传递。而 Hooks 可以让你在函数组件中使用状态和其他 React 特性。

下面是一个使用 Context 和 Hooks 的例子:

import React, { createContext, useState, useContext } from 'react';

const TokenContext = createContext();

function LoginPage() {
  const [token, setToken] = useContext(TokenContext);
  // ...
}

function App() {
  const tokenState = useState(null);

  return (
    <TokenContext.Provider value={tokenState}>
      <LoginPage />
    </TokenContext.Provider>
  );
}

注意,这只是一种基本的使用方法。在实际的项目中,你可能需要创建多个 context,或者使用更复杂的 hooks,例如 useEffectuseReduceruseCallback,等等。你可以查阅 React 的文档来了解更多信息。

猜你喜欢

转载自blog.csdn.net/a871923942/article/details/131253821