react redux理解_我如何最终理解Redux

react redux理解

I have been in charge of setting up a new frontend at work for a new project. Initially I created a new React app using create-react-app, and decided to use React Context API for handling data in the app. I would fetch data when loading the page, save it a in a global state, and then populate it throughout the app using Context. This worked in the beginning, but I quickly realised that It got quite complicated handling a lot of data after a while. I also stored information about ui state in at a Context level, for things like if sidebars and navigation menus are open.

我负责为新项目在工作中设置新的前端。 最初,我使用create-react-app创建了一个新的React应用,并决定使用React Context API来处理应用中的数据。 我将在加载页面时获取数据,将其保存为全局状态,然后使用Context在整个应用程序中填充数据。 这从一开始就起作用,但是我很快意识到,过一会儿处理很多数据变得相当复杂。 我还在上下文级别存储有关ui状态的信息,例如是否打开了侧边栏和导航菜单。

We also wanted to be able to listen to events sent by our backend API to then update state with new data throughout the app. Since we also didn’t store every entity at the Context level this got quite complicated. We started having multiple sources of truths and manually managing a lot of state updating. I decided to start looking towards Redux — a global state management tool I had been using at my previous job. I hadn’t had a lot of good experiences with it, and I was quite ___ towards actually taking a look at it again. However, I spun up a playground for trying it out, watched some tutorials, and hashed out some strategies. Here’s what I learned.

我们还希望能够监听后端API发送的事件,然后使用整个应用程序中的新数据更新状态。 由于我们也没有在上下文级别存储每个实体,因此这变得相当复杂。 我们开始拥有多种事实来源,并手动管理大量状态更新。 我决定开始着眼于Redux,这是我在上一份工作中一直使用的全局状态管理工具。 我没有很多很好的经验,因此我很___打算再次查看它。 但是,我在操场上试了一下,看了一些教程,并提出了一些策略。 这是我学到的。

Redux比我们想象的要容易 (Redux is easier than we think)

Redux has this sort of mist around it, as if it’s some sort of black magic library that only a subset of people in the frontend web development industry actually understand. I think we need to get rid of this assumption — since Redux is just a tool for lifting our data state to another layer in our application — away from our components.

Redux周围弥漫着这种迷雾,好像它是某种黑魔法库,前端Web开发行业中只有一部分人真正理解。 我认为我们需要摆脱这种假设-因为Redux只是将数据状态提升到应用程序中另一层的工具-远离组件。

概念 (Concepts)

Redux have some concepts with naming that can be quite deceiving and sound more complicated than they actually are. These are the main concepts in Redux.

Redux的命名概念有些欺骗性,听起来比实际要复杂得多。 这些是Redux中的主要概念。

商店 (Store)

The store is where all data is eventually going to be stored.

存储将最终存储所有数据。

const store = createStore(reducers)

减速器 (Reducer)

The reducer is kind of the exchange point for the incoming actions.

减速器是传入动作的交换点。

switch (action.type) {
case 'GET_TODOS':
...
case 'CREATE_TODO:
...
CASE 'PATCH_TODO':
...
case 'DELETE_TODO':
...
}

行动 (Action)

Actions are the triggers for fetching, patching, deleting and adding to state.

动作是获取,修补,删除和添加状态的触发器。

function createTodo(todo) {
return {
type: 'CREATE_TODO',
payload: todo
}
}

完整的例子 (Full example)

Let’s try a real example. I’m not going to build a simple counter app like every other Redux tutorial does, since it’s not very real case. Let’s build a todo app that actually updates data in a database, and uses Redux for its frontend data layer management. Let’s start by creating a new React app and installing some dependencies.

让我们尝试一个真实的例子。 我不会像其他Redux教程一样构建一个简单的计数器应用程序,因为它不是真实情况。 让我们构建一个todo应用程序,该应用程序实际更新数据库中的数据,并将Redux用于其前端数据层管理。 首先创建一个新的React应用程序并安装一些依赖项。

建立专案 (Create project)

yarn create react-app todo-frontend

安装依赖项 (Install dependencies)

  • redux: Redux is the main library for creating our store.

    redux :Redux是创建商店的主要库。

  • react-redux: Makes it easier to dispatch our actions and getting state.

    react-redux:使调度动作和获取状态变得更加容易。

  • redux-thunk: A middleware that allows us to make async actions.

    redux-thunk:一种中间件,允许我们执行异步操作。

yarn add redux react-redux redux-thunk

This project is going to use Javascript instead of Typescript. You can certainly use Typescript, and in fact, that’s what I’m doing at my project at work, but it does complicate things a little bit more, and it’s probably not useful for this tutorial anyways.

该项目将使用Javascript代替Typescript。 您当然可以使用Typescript,实际上,这就是我在工作中的项目所要做的事情,但是它确实使事情变得更加复杂了,无论如何对于本教程来说它都没有用。

创建减速器 (Create reducer)

Let’s create our Todo reducer that is going to act as the exchange point for our action dispatching. We’re going to need a couple of actions but it’s not very difficult. You can more or less put this file wherever you are. A reducer is no special code, it’s just a regular Javascript function with a switch statement inside of it, that returns the next state.

让我们创建一个Todo减速器,该减速器将用作我们的动作调度的交换点。 我们将需要采取一些行动,但这并不是很难。 无论您身在何处,都可以将这个文件或多或少地放入。 一个reducer并不是特殊的代码,它只是一个普通的Javascript函数,其中带有switch语句,它返回下一个状态。

const initialState = {
data: [],
getLoading: false,
getError: "",createResponse: null,
createLoading: false,
createError: "",patchResponse: null,
patchLoading: false,
patchError: "",deleteResponse: null,
deleteLoading: false,
deleteError: "",
};function todoReducer(state = initialState, action) {
switch (action.type) {
case "GET_TODOS":
return {
...state,
getLoading: true,
getError: "",
};
case "GET_TODOS_SUCCESS":
return {
...state,
data: action.payload,
getLoading: false,
};
case "GET_TODOS_ERROR":
return {
...state,
getLoading: false,
getError: action.payload,
}; case "CREATE_TODO":
return {
...state,
createLoading: true,
createError: "",
};
case "CREATE_TODO_SUCCESS":
return {
...state,
data: [...state.data, action.payload],
createResponse: action.payload,
createLoading: false,
};
case "CREATE_TODO_ERROR":
return {
...state,
createLoading: false,
createError: action.payload,
}; case "PATCH_TODO":
return {
...state,
patchLoading: true,
patchError: "",
};
case "PATCH_TODO_SUCCESS":
return {
...state,
data: state.payload.map((todo) => {
return todo.id === action.payload ? action.payload : todo;
}),
patchResponse: action.payload,
patchLoading: false,
};
case "PATCH_TODO_ERROR":
return {
...state,
patchLoading: false,
patchError: action.payload,
}; case "DELETE_TODO":
return {
...state,
patchLoading: true,
patchError: "",
};
case "DELETE_TODO_SUCCESS":
return {
...state,
data: state.data.filter((todo) => todo.id !== action.payload),
patchResponse: action.payload,
patchLoading: false,
};
case "DELETE_TODO_ERROR":
return {
...state,
patchLoading: false,
patchError: action.payload,
};
default:
return state;
}
}export default todoReducer;

组合减速器 (Combine reducers)

In a big project we would most likely have more than one reducer. You usually tend to have 1 reducer for each entity. For example, if you have a project containing todos, events, and friends. You would probably want to have a matching reducer for each of them. Anyways, let’s use the function for combining multiple reducers before creating our store, just to show how this would look in a larger project.

在一个大型项目中,我们很可能将有多个减速器。 通常,每个实体通常有1个reducer。 例如,如果您有一个包含待办事项,事件和朋友的项目。 您可能希望为它们每个都配备一个匹配的减速器。 无论如何,让我们在创建商店之前使用该功能将多个reducer组合在一起,只是为了展示它在较大项目中的外观。

import { combineReducers } from "redux";
import todoReducer from "./todo";const rootReducer = combineReducers({
todo: todoReducer,
});export default rootReducer;

建立店铺 (Create store)

Now that we have created our reducer and combined it to create root reducer, we are ready to create our store. Let’s create a new file and create our store.

现在,我们已经创建了Reducer并将其组合为根Reducer,我们准备创建我们的商店。 让我们创建一个新文件并创建我们的商店。

import { createStore, applyMiddleware } from "redux";
import rootReducer from "./reducers";
import thunk from "thunk"const store = createStore(rootReducer, applyMiddleware(thunk));export default store;

Now you have created your store. Although we’re going to add another thing, called Redux devtools. This is a really helpful Chrome extension that lets you see exactly what your store looks like at any moment, as well as what actions are being triggered in real time. To install this we just need to update our store creation like the following.

现在,您已经创建了商店。 尽管我们要添加另一件事,称为Redux devtools。 这是一个非常有用的Chrome扩展程序,可让您随时准确了解商店的外观以及实时触发的操作。 要安装它,我们只需要更新商店创建,如下所示。

import { applyMiddleware, compose, createStore } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";const store = createStore(
rootReducer,
compose(
applyMiddleware(thunk),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);export default store;

包装您的应用 (Wrap your app)

Now, let’s wrap our app using the provider component from react-redux, to make sure data will be accessible anywhere inside of our application.

现在,让我们使用react-redux的提供程序组件包装我们的应用程序,以确保可以在应用程序内的任何位置访问数据。

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";import { Provider } from "react-redux";
import store from "./store";
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById("root")
);

写动作 (Write actions)

The last thing we can do before we jump over to our React components is to write the actions we are going to call when we want to update the state. Let’s create a new file for doing this.

在跳到React组件之前,我们要做的最后一件事就是编写要更新状态时要调用的动作。 让我们为此创建一个新文件。

export function getTodos() {
return async (dispatch) => {
dispatch({
type: "GET_TODOS",
}); try {
const todos = await api.getTodos(); dispatch({
type: "GET_TODOS_SUCCESS",
payload: todos,
});
} catch (err) {
dispatch({
type: "GET_TODOS_SUCCESS",
payload: err.message || "Failed to get todos!",
});
}
};
}export function createTodo(title) {
return async (dispatch) => {
dispatch({
type: "CREATE_TODO",
}); try {
const todo = await api.createTodo(title); dispatch({
type: "CREATE_TODO_SUCCESS",
payload: todo,
});
} catch (err) {
dispatch({
type: "CREATE_TODO_SUCCESS",
payload: err.message || "Failed to create todo!",
});
}
};
}export function patchTodo(id, title) {
return async (dispatch) => {
dispatch({
type: "PATCH_TODO",
}); try {
const newTodo = api.patchTodo(id, title); dispatch({
type: "PATCH_TODO_SUCCESS",
payload: newTodo,
});
} catch (err) {
dispatch({
type: "PATCH_TODO_SUCCESS",
payload: err.message || "Failed to patch todo!",
});
}
};
}export function deleteTodo(id) {
return async (dispatch) => {
dispatch({
type: "DELETE_TODO",
}); try {
await api.deleteTodo(id); dispatch({
type: "DELETE_TODO_SUCCESS",
payload: id,
});
} catch (err) {
dispatch({
type: "DELETE_TODO_SUCCESS",
payload: err.message || "Failed to delete todo!",
});
}
};
}

React成分 (React component)

Now we have finally set up our reducers, actions and our store. Now we can start creating our React component that’s actually going to let the users create, patch, and delete their todos. We are going to use 2 hooks here. The useDispatch and the useSelector. The latter is going to enable us to pick and choose what data we want from our store. And the first one is going to let us dispatch our actions, and therefor connect them to redux, since they’re currently just regular Javascript functions.

现在,我们终于建立了减速器,动作和商店。 现在我们可以开始创建React组件,该组件实际上将允许用户创建,修补和删除他们的待办事项。 我们将在这里使用2个钩子。 useDispatch和useSelector。 后者将使我们能够从商店中选择想要的数据。 第一个是让我们调度动作,并因此将它们连接到redux,因为它们目前只是常规的Javascript函数。

import React from "react";
import { useDispatch, useSelector } from "react-redux";import { createTodo, deleteTodo, patchTodo } from "./store/actions/todo";function App() { const dispatch = useDispatch();
const { data: todos } = useSelector((state) => state.todo);
useEffect(() => {
dispatch(getTodos())
}, [dispatch]) return (
<div>
<button
onClick={() =>
dispatch(createTodo(`Buy oat milk (todo ${todos.length + 1})`))
}
>
Create todo
</button> <ul>
{todos.map((todo) => (
<li key={todo.id}>
<span>{todo.title}</span> <button
style={{ marginLeft: "1rem" }}
onClick={() =>
dispatch(patchTodo(todo.id, `${todo.title}(edited)`))
}
>
Edit todo
</button> <button
style={{ marginLeft: "1rem" }}
onClick={() => dispatch(deleteTodo(todo.id))}
>
Delete todo
</button>
</li>
))}
</ul>
</div>
);
}export default App;

Now your page should list out every todo from whatever backend and database you are using. By updating and deleting todos we’re going to update our global redux state and therefor get new data through our select hook. If we want to see what’s actually happening, we can open up the Chrome Redux devtools. Here you can see every action happening in real time.

现在,您的页面应列出您正在使用的任何后端和数据库中的每个待办事项。 通过更新和删除待办事项,我们将更新全局redux状态,并通过选择钩子获取新数据。 如果我们想查看实际情况,可以打开Chrome Redux devtools。 在这里,您可以实时查看每个动作。

Image for post

成功 (Success)

Now we have built a fully functional React app that uses Redux to globally store, create, and update data. We have also, in the meantime, moved the data layer to another place in our app. Instead of setting and updating state in our React components, we do this in the actions and reducers which makes our components a lot cleaner and easier to update in the future.

现在,我们已经构建了一个功能齐全的React应用,该应用使用Redux来全局存储,创建和更新数据。 同时,我们还将数据层移动到了应用程序中的另一个位置。 我们无需在React组件中设置和更新状态,而是在操作和缩减器中执行此操作,这使我们的组件更加整洁,将来更容易更新。

翻译自: https://medium.com/javascript-in-plain-english/how-i-finally-understood-redux-ffb7666fab43

react redux理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值