我正在学习React Native,并使用TypeScript正确设置了React Navigation。现在我要添加Redux。我尝试实现与React(web)相同的方式。
但是似乎在React Native中缺少一些东西,TodoItem
组件和TodoScreen
出现了,但是我无法添加或删除。
// MyTypes.d.ts
declare module 'MyTypes' {
import { StateType, ActionType } from 'typesafe-actions';
// 1 for reducer, 1 for action creators
// export type ReducerState = StateType<typeof import('../reducers').default>;
export type ReducerState = StateType<typeof import('../reducers/todo').default>;
export type RootAction = ActionType<typeof import('../actions').default>;
}
// actions/todo.tsx
import { action } from 'typesafe-actions';
export enum TodoActionTypes {
ADD = 'ADD',
DELETE = 'DELETE'
}
export const todoActions = {
add: (item: string) => action(TodoActionTypes.ADD, item),
delete: (idx: number) => action(TodoActionTypes.DELETE, idx)
};
// reducers/todo.tsx
import * as MyTypes from 'MyTypes';
import { TodoActionTypes } from '../actions/todo';
interface TodoModel {
count: number;
list: string[];
}
export const initialState: TodoModel = {
count: 2,
list: ['Do the laundry', 'Do the dishes']
};
export const todoReducer = (
state: TodoModel = initialState,
action: MyTypes.RootAction
) => {
switch (action.types) {
case TodoActionTypes.ADD: {
return {
...state,
count: state.count + 1,
list: [...state.list, action.payload]
};
}
case TodoActionTypes.DELETE: {
const oldList = [...state.list];
oldList.splice(action.payload, 1);
const newList = oldList;
return {
...state,
count: state.count - 1,
list: newList
};
}
default:
return state;
}
};
// Store.tsx
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';
import { combineReducers, createStore, applyMiddleware, compose } from 'redux';
import { todoReducer } from './reducers/todo';
const middleware: any = [thunk];
if (process.env.NODE_ENV !== 'production') {
middleware.push(createLogger());
}
// @ts-ignore
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const rootReducer = combineReducers({
todo: todoReducer
});
const Store = createStore(
rootReducer,
composeEnhancer(applyMiddleware(...middleware))
);
export default Store;
// App.tsx
import React from 'react';
import { Provider } from 'react-redux';
import Store from './Store';
import AppContainer from './navigation/AppContainer';
export default function App() {
return (
<Provider store={Store}>
<AppContainer />
</Provider>
);
}
// TodoItem.tsx
import React from 'react';
import { View, Text, Button } from 'react-native';
interface Props {
item: string;
idx: number;
handleDelete: (idx: number) => void;
}
const TodoItem: React.FC<Props> = props => {
return (
<View>
<Text>{props.item}</Text>
<Button title="X" onPress={() => props.handleDelete(props.idx)} />
</View>
);
};
export default TodoItem;
// TodoScreen.tsx
import React, { Component } from 'react';
import { Dispatch } from 'redux';
import * as MyTypes from 'MyTypes';
import { connect } from 'react-redux';
import { View, Button, Text, TextInput } from 'react-native';
import TodoItem from '../components/TodoItem';
import { TodoActionTypes } from '../actions/todo';
interface State {
todoInput: string;
}
interface Props {
count: number;
todoList: string[];
addTodo: (item: string) => object;
deleteTodo: (idx: number) => object;
}
class TodoScreen extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
todoInput: ''
};
}
handleTextChange = (text: any) => {
this.setState({
todoInput: text
});
};
handleAddButtonClick = () => {
this.props.addTodo(this.state.todoInput);
this.setState({
todoInput: ''
});
};
handleDeleteButtonClick = (idx: number) => {
console.log('Deleting: ', idx);
this.props.deleteTodo(idx);
};
render() {
let todoJSX: JSX.Element[] | JSX.Element;
if (!this.props.todoList.length) {
todoJSX = <p>Nothing to do</p>;
} else {
todoJSX = this.props.todoList.map((item, idx) => {
return (
<TodoItem
key={idx}
item={item}
idx={idx}
handleDelete={this.handleDeleteButtonClick}
/>
);
});
}
return (
<View>
{todoJSX}
<TextInput
editable={true}
value={this.state.todoInput}
placeholder={'New To Do Here'}
onChangeText={this.handleTextChange}
/>
<Button title="Add To Do" onPress={this.handleAddButtonClick} />
</View>
);
}
}
const MapStateToProps = (store: MyTypes.ReducerState) => {
return {
count: store.todo.count,
todoList: store.todo.list
};
};
const MapDispatchToProps = (dispatch: Dispatch<MyTypes.RootAction>) => ({
addTodo: (item: string) =>
dispatch({ type: TodoActionTypes.ADD, payload: item }),
deleteTodo: (idx: number) =>
dispatch({ type: TodoActionTypes.DELETE, payload: idx })
});
export default connect(
MapStateToProps,
// @ts-ignore
MapDispatchToProps
)(TodoScreen);
对不起,这堆代码。如果您需要,这里是完整的回购清单:https://github.com/Mexman2Rowen/so-nav-dux我试图将其降至最低。