Redux+Hook 重写 Todo List,用代码实例挽回摒弃 Redux 的用户

栏目: IOS · Android · 发布时间: 5年前

内容简介:作者开发了一个名为“reactive-react-redux”的库,尽管它基于 Redux,但和传统方法又有一些区别。作者基于这个库给出了 Redux 中 Todo List 的示例代码。如果你已经在用 React Redux 并爱上它,可能会不理解为什么人们尝试使用 React 中的 context 和 hook 来替换 Redux,即所谓“去 Redux 化”。有些人认为 Redux DevTools 的扩展工具和中间件蛮不错的,对于他们来说,Redux 和 context + hook 实际上是两种选

作者开发了一个名为“reactive-react-redux”的库,尽管它基于 Redux,但和传统方法又有一些区别。作者基于这个库给出了 Redux 中 Todo List 的示例代码。

如果你已经在用 React Redux 并爱上它,可能会不理解为什么人们尝试使用 React 中的 context 和 hook 来替换 Redux,即所谓“去 Redux 化”。

有些人认为 Redux DevTools 的扩展 工具 和中间件蛮不错的,对于他们来说,Redux 和 context + hook 实际上是两种选项。Context + hook 可以在组件之间实现状态共享,但是随着 APP 变得越来越大,有可能还是需要引入 Redux 或其他类似的解决方案,否则,最终运行中会出现太多上下文而无法进行顺畅处理。但是,我得承认这只是假设,将来或许能够找到更好的解决方案。

我最近一直在开发一个名为“reactive-react-redux”的库,尽管它基于 Redux,但和传统方法又有一些区别。Github 地址: https://github.com/dai-shi/reactive-react-redux

它的 API 非常简单直观,而且 Proxy 让它的性能得到了优化。我希望这个库能挽回一些用 context + hook 去替代 Redux 的开发人员,为此我还基于这个库写了代码示例。下面这个 示例 实现的是 Redux 中著名的 Todo List。

这个示例是用 TypeScript 语言写的。如果你不熟悉 TypeScript,请尝试忽略 State、Action 和 *Type 这些关键字。

类型定义和状态还原器(reducer)

State 和 Action 的类型定义定义如下:

./src/types/index.ts

复制代码

exporttypeVisibilityFilterType =
|'SHOW_ALL'
|'SHOW_COMPLETED'
|'SHOW_ACTIVE';

exporttypeTodoType = {
id:number;
text:string;
completed:boolean;
};

exporttypeState = {
todos: TodoType[];
visibilityFilter: VisibilityFilterType;
};

exporttypeAction =
| {type:'ADD_TODO'; id:number; text:string}
| {type:'SET_VISIBILITY_FILTER'; filter: VisibilityFilterType }
| {type:'TOGGLE_TODO'; id:number};

状态还原器(reducer)的代码几乎与原始示例一样,如下所示。

./src/reducers/index.ts

复制代码

import{ combineReducers }from'redux';

importtodosfrom'./todos';
importvisibilityFilterfrom'./visibilityFilter';

exportdefaultcombineReducers({
todos,
visibilityFilter,
});

./src/reducers/todos.ts

复制代码

import { TodoType, Action }from'../types';

const todos = (state: TodoType[] = [], action: Action): TodoType[] => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false,
},
];
case 'TOGGLE_TODO':
returnstate.map((todo: TodoType) => (
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
));
default:
returnstate;
}
};

exportdefaulttodos;

./src/reducers/visibilityFilter.ts

复制代码

import{ Action, VisibilityFilterType }from'../types';

constvisibilityFilter = (
state: VisibilityFilterType ='SHOW_ALL',
action: Action,
):VisibilityFilterType=>{
switch(action.type) {
case'SET_VISIBILITY_FILTER':
returnaction.filter;
default:
returnstate;
}
};

exportdefaultvisibilityFilter;

动作生成器(Action creators)

有几种方法都可以用来实现动作分派。而我的选择是为每个动作创建 hook。注意,这方面我们仍在探索更好的实现方式。

./src/actions/index.ts

复制代码

import{ useCallback }from'react';
import{ useReduxDispatch }from'reactive-react-redux';

import{ Action, VisibilityFilterType }from'../types';

letnextTodoId =0;

exportconstuseAddTodo =()=>{
constdispatch = useReduxDispatch<Action>();
returnuseCallback((text:string) =>{
dispatch({
type:'ADD_TODO',
id: nextTodoId++,
text,
});
}, [dispatch]);
};

exportconstuseSetVisibilityFilter =()=>{
constdispatch = useReduxDispatch<Action>();
returnuseCallback((filter: VisibilityFilterType) =>{
dispatch({
type:'SET_VISIBILITY_FILTER',
filter,
});
}, [dispatch]);
};

exportconstuseToggleTodo =()=>{
constdispatch = useReduxDispatch<Action>();
returnuseCallback((id:number) =>{
dispatch({
type:'TOGGLE_TODO',
id,
});
}, [dispatch]);
};

以上实现其实并非真正意义上的动作生成器,而是返回动作分派器的 hook。

组件

我们并不在这里区分演示组件(presentational components)和容器组件(container components)。当然如何构造组件仍然是个值得探讨的话题,但是在本例中,组件都被视为扁平的。

./src/components/App.tsx:App 也和原始示例保持一致。

复制代码

import*asReactfrom'react';

importFooterfrom'./Footer';
importAddTodofrom'./AddTodo';
importVisibleTodoListfrom'./VisibleTodoList';

constApp: React.FC =()=>(
<div>
<AddTodo/>
<VisibleTodoList/>
<Footer/>
</div>
);

exportdefaultApp;

./src/components/Todo.tsx:这里做了一些小的修改,但没有特别大的改动。

复制代码

import*asReactfrom'react';

type Props = {
onClick:(e: React.MouseEvent) =>void;
completed: boolean;
text: string;
};

constTodo: React.FC<Props> =({ onClick, completed, text }) =>(
<li
onClick={onClick}
role="presentation"
style={{
textDecoration:completed? 'line-through':'none',
cursor:'pointer',
}}
>
{text}
</li>
);

exportdefaultTodo;

./src/components/VisibleTodoList.tsx:这里并未出现 mapStateToProps 或 selector 函数,只是在 render 中调用 getVisibleTodos。

复制代码

import*asReactfrom'react';
import{ useReduxState }from'reactive-react-redux';

import{ TodoType, State, VisibilityFilterType }from'../types';
import{ useToggleTodo }from'../actions';
importTodofrom'./Todo';

constgetVisibleTodos =(todos: TodoType[], filter: VisibilityFilterType) =>{
switch(filter) {
case'SHOW_ALL':
returntodos;
case'SHOW_COMPLETED':
returntodos.filter(t=>t.completed);
case'SHOW_ACTIVE':
returntodos.filter(t=>!t.completed);
default:
thrownewError(`Unknown filter:${filter}`);
}
};

constVisibleTodoList: React.FC =()=>{
conststate = useReduxState<State>();
constvisibleTodos = getVisibleTodos(state.todos, state.visibilityFilter);
consttoggleTodo = useToggleTodo();
return(
<ul>
{visibleTodos.map(todo => (
<Todokey={todo.id}{...todo}onClick={()=>toggleTodo(todo.id)} />
))}
</ul>
);
};

export default VisibleTodoList;

./src/components/FilterLink.tsx:同样,当 useReduxState 函数返回整个 Redux 状态对象时,程序只是使用其属性对 active 进行评估。

复制代码

import*asReactfrom'react';
import{ useReduxState }from'reactive-react-redux';

import{ useSetVisibilityFilter }from'../actions';
import{ State, VisibilityFilterType }from'../types';

type Props = {
filter: VisibilityFilterType;
};

constFilterLink: React.FC<Props> =({ filter, children }) =>{
conststate = useReduxState<State>();
constactive = filter === state.visibilityFilter;
constsetVisibilityFilter = useSetVisibilityFilter();
return(
<button
type="button"
onClick={()=> setVisibilityFilter(filter)}
disabled={active}
style={{
marginLeft: '4px',
}}
>
{children}
</button>
);
};

exportdefaultFilterLink;

./src/components/Footer.tsx:由于有类型检查的保证,可以将字符串传递给 FilterLink 组件的 filter 属性。

复制代码

import*asReactfrom'react';

importFilterLinkfrom'./FilterLink';

constFooter: React.FC =()=>(
<div>
<span>Show:</span>
<FilterLinkfilter="SHOW_ALL">All</FilterLink>
<FilterLinkfilter="SHOW_ACTIVE">Active</FilterLink>
<FilterLinkfilter="SHOW_COMPLETED">Completed</FilterLink>
</div>
);

exportdefaultFooter;

./src/components/AddTodo.tsx:这里对原始示例进行了一些修改,以便使用带有 useState 的受控表单。

复制代码

import*asReactfrom'react';
import{ useState }from'react';

import{ useAddTodo }from'../actions';

constAddTodo =()=>{
const[text, setText] = useState('');
constaddTodo = useAddTodo();
return(
<div>
<form
onSubmit={(e)=> {
e.preventDefault();
if (!text.trim()) {
return;
}
addTodo(text);
setText('');
}}
>
<inputvalue={text}onChange={e=>setText(e.target.value)} />
<buttontype="submit">Add Todo</button>
</form>
</div>
);
};

export default AddTodo;

在线演示

请打开你的浏览器访问 codesandbox ,运行该示例。你也可以在 GitHub 上找到所有源代码。

其他信息

这篇文章中,并没有解释关于 reactive- response -redux 的内部细节。请访问 GitHub 查看更多信息。

英文原文: https://blog.axlight.com/posts/redux-meets-hooks-for-non-redux-users-a-small-concrete-example-with-reactive-react-redux/

Redux+Hook 重写 Todo List,用代码实例挽回摒弃 Redux 的用户


以上所述就是小编给大家介绍的《Redux+Hook 重写 Todo List,用代码实例挽回摒弃 Redux 的用户》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入解析Spring MVC与Web Flow

深入解析Spring MVC与Web Flow

Seth Ladd、Darren Davison、Steven Devijver、Colin Yates / 徐哲、沈艳 / 人民邮电出版社 / 2008-11 / 49.00元

《深入解析Spring MVCgn Web Flow》是Spring MVC 和Web Flow 两个框架的权威指南,书中包括的技巧和提示可以让你从这个灵活的框架中汲取尽可能多的信息。书中包含了一些开发良好设计和解耦的Web 应用程序的最佳实践,介绍了Spring 框架中的Spring MVC 和Spring Web Flow,以及着重介绍利用Spring 框架和Spring MVC 编写Web ......一起来看看 《深入解析Spring MVC与Web Flow》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换