本篇博客我们将继续完善处理错误,显示加载指示器,实现表单验证,处理跨域请求等。
错误处理:
在前端代码中,我们应当为所有网络请求添加错误处理逻辑。例如,如果后端返回了一个错误码,我们应当在前端捕获到这个错误,并向用户显示一个错误消息。
这里是一个简单的错误处理的例子:
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的内置验证功能,或者yup
,joi
等库。
这是一个使用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
提供的 Provider
和 connect
函数来连接你的 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,例如 useEffect
,useReducer
,useCallback
,等等。你可以查阅 React 的文档来了解更多信息。