React状态管理解决方案
今天我将用一个简单的博客程序,来展示React现在常用三种不同状态管理方案。
纯React hooks
Redux
Context
下面来看每种方式
纯React Hooks 方式
当我们的应用还不够大时,使用React Hools的响应式数据处理方式足够我们日常开发应用。
例子
import Posts from "./Components/Posts"; import PostForm from "./Components/PostForm"; import { useState } from "react"; const App = () => { const [PostData, setPostData] = useState([]); const addPost = (formData) => { setPostData([formData, ...PostData]); }; return ( <div className="app-container"> <h1>React hooks 方式</h1> <PostForm addPost={addPost} /> <Posts setPostData={setPostData} PostData={PostData} /> </div> ); }; export default App;
在上面的代码中,PostForm组件和Posts组件都需要传入相同props,如果应用中还有很多相同的兄弟组件,那么我们将每个组件都需要传入props。
如果有嵌套多层的组件结构,那么就需要一层一层的props进行传递,直到最深的子组件。
所以,这时我们就需要一个能够集中管理数据的地方,这时Redux出场了
状态管理 Redux
Redux是最出名的,也是最早的,使用人数较多的状态管理解决方案。
但学习Redux也很头疼,首先它有很多的理念需要知道,然后在项目中配置Redux还需要大量的代码。
Redux基于伟大的Flux架构,它主要提供actions和reducers和全局store来让我们管理状态。
Flux架构可以理解为基于事件驱动状态,比如用户点击按钮,或者提交表单,页面首次加载等等。当发生这些动作时会触发action处理函数更新状态,状态变化导致用户界面也会变化,需要更新状态的组件会在全局store进行订阅,一旦reducers对状态进行任何更改,就会立即收到更新。简单理解就是发布订阅的设计模式。
React中的Redux状态管理需要redux和react-redux两个依赖库。
例子
import { Provider } from "react-redux";
import store from "./store";
import Posts from "./Components/Posts";
import PostForm from "./Components/PostForm";
const App = () => (
<Provider store={store}>
<div className="app-container">
<h1>使用Redux管理状态</h1>
<PostForm />
<Posts />
</div>
</Provider>
);
export default App;
这时我们可以看到, PostForm组件和Posts组件不再需要传入props,就可以在组件内使用和修改全局store中的状态。
但是,还有但是,我们需要在组件内多写很多的代码才能实现这一点,主要看组件的最后两行代码。
PostForm组件代码
import { useState } from "react";
import { connect } from "react-redux";
import { object } from "prop-types";
import { createNewPost } from "../actions/postActions";
const initialFormState = { title: "", body: "" };
const PostForm = ({ createNewPost }) => {
const [formData, setFormData] = useState(initialFormState);
const handleChange = (ev) => {
setFormData({
...formData,
[ev.target.name]: ev.target.value,
});
};
const handlePostIt = (ev) => {
ev.preventDefault();
createNewPost(formData);
setFormData(initialFormState);
};
return (
<div className="postform-container">
<label htmlFor="title">Title</label>
<input
type="text"
name="title"
onChange={handleChange}
value={formData.title}
/>
<br />
<label htmlFor="body">Post</label>
<textarea name="body" onChange={handleChange} value={formData.body} />
<br />
<button type="submit" onClick={handlePostIt}>
发布
</button>
</div>
);
};
const mapStateToProps = (state) => ({});
export default connect(mapStateToProps, { createNewPost })(PostForm);
Posts组件代码
import { useEffect } from "react";
import { func, array, object } from "prop-types";
import { connect } from "react-redux";
import { fetchPosts } from "../actions/postActions";
const Posts = ({ posts, fetchPosts }) => {
useEffect(() => {
fetch("/posts")
.then((res) => res.json())
.then((posts) => {
fetchPosts(posts);
});
}, []);
return (
<div className="posts-container">
<div>
<h1>博文列表</h1>
</div>
{posts.map((post, index) => (
<div key={index}>
<div className="post-title">{post.title}</div>
<div className="post-body">{post.body}</div>
</div>
))}
</div>
);
};
Posts.propTypes = {
posts: array.isRequired,
};
const mapStateToProps = (state) => ({
posts: state.posts.items,
});
export default connect(mapStateToProps, { fetchPosts })(Posts);
每个组件后面都需要写这些代码。
到这里你可能说,这和React hooks的方式没差多少,那用Redux的痛点在哪呢?
接着看
reducers/index.js文件
import { combineReducers } from "redux";
import postReducer from "./postReducer";
export default combineReducers({
posts: postReducer,
});
actions文件
import { FETCH_POSTS, NEW_POST } from "./types";
export const fetchPosts = (postsData) => {
return {
type: FETCH_POSTS,
payload: postsData,
};
};
export const createNewPost = (postData) => {
return {
type: NEW_POST,
payload: postData,
};
};
post reducers文件
import { FETCH_POSTS, NEW_POST } from "../actions/types";
const initialState = {
items: [],
item: { title: "", body: "" },
};
const postReducer = (state = initialState, action) => {
if (action.type === FETCH_POSTS) {
return {
...state,
items: action.payload,
};
} else if (action.type === NEW_POST) {
return {
...state,
items: [action.payload, ...state.items],
};
} else return state;
};
export default postReducer;
store状态文件
import { createStore } from "redux";
import rootReducer from "./reducers";
const initialState = {
posts: {
items: [],
item: { title: "标题", body: "内容" },
},
};
const store = createStore(rootReducer, initialState);
export default store;
types文件
export const FETCH_POSTS = "FETCH_POSTS"; export const NEW_POST = "NEW_POST";
这是使用Redux的必备全套配置,第一次配,简直是麻烦要死。
Context 方式
如果现在有一种方式,具备Redux的状态管理架构,而无需大量的配置代码,也无需外部依赖。
是的,这就是React发布了Context作为内置功能,允许我们创建全局的状态。只要几行就可以配置成功。
使用useReducer hook,可以模拟redux的模式,使用Context可以访问程序中任何位置的全局状态,只需要在根节点使用provider包裹即可。
看下面的代码
App.js
import Posts from "./Components/Posts"; import PostForm from "./Components/PostForm"; import { useEffect, createContext, useReducer } from "react"; const appReducer = (state, action) => { switch (action.type) { case "FETCH_POSTS": return [...state, ...action.payload]; case "NEW_POST": return [action.payload, ...state]; default: return state; } }; export const AppContext = createContext(); const App = () => { const [state, dispatch] = useReducer(appReducer, []); return ( <AppContext.Provider value={[state, dispatch]}> <div className="app-container"> <h1>Context 状态管理</h1> <PostForm /> <Posts /> </div> </AppContext.Provider> ); }; export default App;
Posts.js
import { useEffect, useContext } from "react";
import { AppContext } from "../App";
const Posts = () => {
const [state, dispatch] = useContext(AppContext);
useEffect(() => {
fetch("/posts")
.then((res) => res.json())
.then((posts) => {
dispatch({ type: "FETCH_POSTS", payload: posts });
});
}, []);
return (
<div className="posts-container">
<div>
<h1>博文列表</h1>
</div>
{state.map((post, index) => (
<div key={index}>
<div className="post-title">{post.title}</div>
<div className="post-body">{post.body}</div>
</div>
))}
</div>
);
};
export default Posts;
PostForm.js
import { useState, useContext } from "react";
import { AppContext } from "../App";
const PostForm = () => {
const [state, dispatch] = useContext(AppContext);
const [formData, setFormData] = useState({
title: "",
body: "",
});
const handleChange = (ev) => {
setFormData({
...formData,
[ev.target.name]: ev.target.value,
});
};
const handlePostIt = (ev) => {
ev.preventDefault();
dispatch({ type: "NEW_POST", payload: formData });
setFormData({ title: "", body: "" });
};
return (
<div className="postform-container">
<label htmlFor="title">标题</label>
<input
type="text"
name="title"
onChange={handleChange}
value={formData.title}
/>
<br />
<label htmlFor="body">内容</label>
<textarea name="body" onChange={handleChange} value={formData.body} />
<br />
<button type="submit" onClick={handlePostIt}>
发布
</button>
</div>
);
};
export default PostForm;
App.js中的appReducer函数,就相当于替带了Redux中那些烦人的代码。
使用React Hooks和Context就可以用更少的代码实现全局状态管理,而且这些功能已经内置在React中,不再需要三方的依赖。
不过,Redux并不是没有用处,Redux提供的功能也并不只有状态管理,所以需要Redux的其他功能,继续使用Redux就好。
实际上,这三种方式是现在React开发的常用方式,只使用hooks适合简单的小型应用,所以只要在你需要全局状态管理的时候再去选择Redux和Context。
最后
引用Redux 的创造者 Dan Abramov的话
“如果你不知道是否需要 Redux,那就是不需要它。”
“只有遇到 React 实在解决不了的问题,你才需要 Redux 。”
————————————————
版权声明:本文为CSDN博主「小帅的编程笔记」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cmdfas/article/details/120558205

浙公网安备 33010602011771号