📅  最后修改于: 2023-12-03 14:46:57.860000             🧑  作者: Mango
本示例将展示如何使用React和Redux构建一个获取个人信息的web应用,包含基本的增删改查操作。我们将通过一个示例代码,阐述应用如何拥有以下功能:
在开始构建应用之前,请确保您已经安装了Node.js(最好使用最新版本)。 接下来,我们来看看构建步骤:
npm i react react-dom react-redux react-router-dom redux redux-thunk axios
在应用的根目录下创建以下目录:
- src
- components
- Users.js
- User.js
- actions
- userActions.js
- reducers
- userReducer.js
- utils
- api.js
- App.js
- index.js
在这个示例中,我们将使用以下模型:
{
id: 1,
name: 'Mark',
email: 'mark@example.com',
phone: '1234567890'
}
其中,id是唯一的,name,email和phone是字符串类型。
为了模拟这个模型,我们将使用一个数组来存储用户数据,并将id设置为自增的数字。在src/utils/api.js
中创建以下代码:
let users = [
{
id: 1,
name: 'Mark',
email: 'mark@example.com',
phone: '1234567890'
},
{
id: 2,
name: 'John',
email: 'john@example.com',
phone: '4567891230'
}
];
let nextId = 3; //设置初始id为3
export function getUsers() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(users);
}, 1000);
});
}
export function getUserById(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const user = users.find((user) => user.id === id);
if (user) {
resolve(user);
} else {
reject(new Error('User not found'))
}
}, 500);
});
}
export function addUser(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const newUser = {...user, id: nextId++};
users.push(newUser);
resolve(newUser);
}, 500);
});
}
export function updateUser(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const index = users.findIndex((u) => u.id === user.id);
if (index === -1) {
reject(new Error('User not found'));
} else {
users[index] = user;
resolve(user);
}
}, 500);
});
}
export function deleteUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const index = users.findIndex((u) => u.id === id);
if (index === -1) {
reject(new Error('User not found'));
} else {
users.splice(index, 1);
resolve(id);
}
}, 500);
});
}
这段代码模拟了与一个API进行交互的函数,并返回Promise以模拟异步请求。
在上面的代码中,我们定义了五个函数:
getUsers
:返回所有的usersgetUserById
:从id获取特定用户信息addUser
:将一个新用户添加到用户列表中updateUser
:根据id更新用户信息deleteUser
:通过id删除用户信息在src/actions/userActions.js
中,创建以下内容:
import {
FETCH_USERS_REQUEST,
FETCH_USERS_SUCCESS,
FETCH_USERS_FAILURE,
FETCH_USER_REQUEST,
FETCH_USER_SUCCESS,
FETCH_USER_FAILURE,
ADD_USER_REQUEST,
ADD_USER_SUCCESS,
ADD_USER_FAILURE,
UPDATE_USER_REQUEST,
UPDATE_USER_SUCCESS,
UPDATE_USER_FAILURE,
DELETE_USER_REQUEST,
DELETE_USER_SUCCESS,
DELETE_USER_FAILURE
} from '../constants/userConstants';
import * as api from '../utils/api';
//获取所有用户
export const fetchUsers = () => async (dispatch) => {
try {
dispatch({ type: FETCH_USERS_REQUEST });
const data = await api.getUsers();
dispatch({
type: FETCH_USERS_SUCCESS,
payload: data,
})
} catch (error) {
dispatch({
type: FETCH_USERS_FAILURE,
error: error.message,
});
}
};
//根据id获取用户
export const fetchUserById = (id) => async (dispatch) => {
try {
dispatch({ type: FETCH_USER_REQUEST });
const data = await api.getUserById(id);
dispatch({
type: FETCH_USER_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: FETCH_USER_FAILURE,
error: error.message,
});
}
};
//添加用户
export const addUser = (user) => async (dispatch) => {
try {
dispatch({ type: ADD_USER_REQUEST });
const data = await api.addUser(user);
dispatch({
type: ADD_USER_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: ADD_USER_FAILURE,
error: error.message,
});
}
};
//更新用户信息
export const updateUser = (user) => async (dispatch) => {
try {
dispatch({ type: UPDATE_USER_REQUEST });
const data = await api.updateUser(user);
dispatch({
type: UPDATE_USER_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: UPDATE_USER_FAILURE,
error: error.message,
});
}
};
//删除用户信息
export const deleteUser = (id) => async (dispatch) => {
try {
dispatch({ type: DELETE_USER_REQUEST });
const data = await api.deleteUser(id);
dispatch({
type: DELETE_USER_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: DELETE_USER_FAILURE,
error: error.message,
});
}
};
这里我们定义了五个功能,每一个功能都是一个异步函数。当我们调用其中的一个函数时,它会分派一个action到store,并执行适当的逻辑,最终更新状态并重新渲染与该状态对应的UI。
在src/reducers/userReducer.js
中,我们将创建一个Reducer来处理我们User的action和状态。
import {
FETCH_USERS_REQUEST,
FETCH_USERS_SUCCESS,
FETCH_USERS_FAILURE,
FETCH_USER_REQUEST,
FETCH_USER_SUCCESS,
FETCH_USER_FAILURE,
ADD_USER_REQUEST,
ADD_USER_SUCCESS,
ADD_USER_FAILURE,
UPDATE_USER_REQUEST,
UPDATE_USER_SUCCESS,
UPDATE_USER_FAILURE,
DELETE_USER_REQUEST,
DELETE_USER_SUCCESS,
DELETE_USER_FAILURE,
} from '../constants/userConstants';
const initialState = {
users: [],
user: null,
loading: false,
error: null
}
export const userReducer = (state = initialState, action) => {
switch(action.type) {
case FETCH_USERS_REQUEST:
return {
...state,
loading: true,
error: null,
};
case FETCH_USERS_SUCCESS:
return {
...state,
loading: false,
error: null,
users: action.payload,
};
case FETCH_USERS_FAILURE:
return {
...state,
loading: false,
error: action.error
};
case FETCH_USER_REQUEST:
return {
...state,
loading: true,
error: null,
};
case FETCH_USER_SUCCESS:
return {
...state,
loading: false,
error: null,
user: action.payload,
};
case FETCH_USER_FAILURE:
return {
...state,
loading: false,
error: action.error
};
case ADD_USER_REQUEST:
return {
...state,
loading: true,
error: null
};
case ADD_USER_SUCCESS:
return {
...state,
loading: false,
error: null,
users: [ ...state.users, action.payload ]
};
case ADD_USER_FAILURE:
return {
...state,
loading: false,
error: action.error
};
case UPDATE_USER_REQUEST:
return {
...state,
loading: true,
error: null
};
case UPDATE_USER_SUCCESS:
return {
...state,
loading: false,
error: null,
users: state.users.map((user) => {
if (user.id === action.payload.id) {
return { ...user, ...action.payload };
} else {
return user;
}
}),
user: action.payload
};
case UPDATE_USER_FAILURE:
return {
...state,
loading: false,
error: action.error
};
case DELETE_USER_REQUEST:
return {
...state,
loading: true,
error: null
};
case DELETE_USER_SUCCESS:
return {
...state,
loading: false,
error: null,
users: state.users.filter((user) => user.id !== action.payload)
};
case DELETE_USER_FAILURE:
return {
...state,
loading: false,
error: action.error
};
default:
return state;
}
};
这是一个标准的Redux Reducer,用于根据action更新应用程序的状态。当我们调用一个异步操作中的某一个case
时,会执行对应的逻辑,最终返回一个新的state。
在src/components/Users.js
中,我们创建一个简单的React组件,用于获取所有用户:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUsers } from '../actions/userActions';
const Users = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchUsers());
}, [dispatch]);
const users = useSelector((state) => state.userReducer.users);
const loading = useSelector((state) => state.userReducer.loading);
const error = useSelector((state) => state.userReducer.error);
return (
<div>
<h1>Users</h1>
{loading && <em>Loading users...</em>}
{error && <p style={{ color: 'red' }}>{error}</p>}
{!loading && users.length === 0 && <p>No users added yet.</p>}
{users.length > 0 && (
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
<td>{user.phone}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
)
}
export default Users;
在这个组件中,我们使用了React Hooks和React-Redux来获取我们的用户数据,并在页面渲染中输出。
在src/components/User.js
中,我们可以创建一个用于特定用户的组件。
import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUserById, addUser, updateUser, deleteUser } from '../actions/userActions';
const INITIAL_STATE = { name: '', email: '', phone: '' };
const User = ({ match, history }) => {
const [user, setUser] = useState(INITIAL_STATE);
const [isSubmitting, setIsSubmitting] = useState(false);
const [errors, setErrors] = useState({});
const { id } = match.params;
const dispatch = useDispatch();
const singleUser = useSelector((state) => state.userReducer.user);
const loading = useSelector((state) => state.userReducer.loading);
const error = useSelector((state) => state.userReducer.error);
const handleChange = (e) => setUser({ ...user, [e.target.name]: e.target.value.trim() });
const validate = () => {
let newErrors = {};
if (!user.name) {
newErrors.name = 'Please provide the name!';
}
if (!user.email) {
newErrors.email = 'Please provide the email!';
}
if (!user.phone) {
newErrors.phone = 'Please provide the phone!';
}
return newErrors;
}
const handleSubmit = (e) => {
e.preventDefault();
setIsSubmitting(true);
setErrors(validate());
if (Object.keys(errors).length === 0) {
if (!id) {
dispatch(addUser(user)).then(() => history.push('/users'));
} else {
dispatch(updateUser(user)).then(() => history.push('/users'));
}
} else {
setIsSubmitting(false);
}
};
const handleDelete = () => {
if (window.confirm('Are you sure to delete this user?')) {
dispatch(deleteUser(id)).then(() => history.push('/users'));
}
}
useEffect(() => {
if (id) {
dispatch(fetchUserById(id));
}
}, [dispatch, id]);
useEffect(() => {
if (!isSubmitting) {
setErrors({});
setUser(singleUser || INITIAL_STATE);
}
}, [singleUser, isSubmitting]);
return (
<div>
{loading && <em>Loading user...</em>}
{error && <p style={{ color: 'red' }}>{error}</p>}
{user && (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input type="text" id="name" name="name" value={user.name} onChange={handleChange} />
{errors.name && <p style={{ color: 'red' }}>{errors.name}</p>}
</div>
<div>
<label htmlFor="email">Email:</label>
<input type="email" id="email" name="email" value={user.email} onChange={handleChange} />
{errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
</div>
<div>
<label htmlFor="phone">Phone:</label>
<input type="text" id="phone" name="phone" value={user.phone} onChange={handleChange} />
{errors.phone && <p style={{ color: 'red' }}>{errors.phone}</p>}
</div>
<div>
<button type="submit" disabled={isSubmitting}>Save</button>
{id && <button type="button" onClick={handleDelete}>Delete</button>}
<button type="button" onClick={() => history.push('/users')}>Cancel</button>
</div>
</form>
)}
</div>
);
};
export default User;
在这里,我们创建了一个React Hook函数组件,用于处理单个用户的渲染和逻辑。我们可以简单地调用该组件来显示特定的用户信息并进行简单编辑。
最后,在src/App.js
中,我们定义我们的主App组件,并通过React Router Dom
将其连接到Users和User组件。
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Users from './components/Users';
import User from './components/User';
const App = () => (
<Router>
<Switch>
<Route exact path="/users" component={Users} />
<Route exact path="/users/:id" component={User} />
</Switch>
</Router>
);
export default App;
最后,我们在src/index.js
中渲染我们构建的应用。将我们的App组件包裹在Redux和Redux-Thunk Provider中,以便使用我们的store和操作。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import App from './App';
import { userReducer } from './reducers/userReducer';
const store = createStore(userReducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
这样,我们的应用就完成了,并拥有了基本的增删改查使用。
在本文中,我们演示了使用React和Redux创建一个简单的应用程序的步骤。我们学习了如何创建Reducer、Action和React组件来处理我的数据和逻辑。对于React和Redux的初学者而言,这种构建方式可以使我们更好地理解如何使用这两个库。