React Native 和 Redux 是两个非常流行的前端技术,它们可以让我们快速构建跨平台的移动应用程序。在本文中,我们将探讨如何在 React Native 和 Redux 上构建可扩展的应用程序,包括如何设计应用程序的架构,如何管理应用程序的状态,以及如何处理异步操作。
设计应用程序的架构
在构建任何应用程序之前,我们需要先考虑应用程序的架构。在 React Native 中,我们可以使用 Flux 架构或 Redux 架构来管理应用程序的状态。在这篇文章中,我们将使用 Redux 架构。
Redux 架构包含三个主要部分:store、action 和 reducer。Store 是应用程序的状态管理器,它包含了所有的应用程序状态。Action 是一个描述应用程序状态变化的对象。Reducer 是一个纯函数,它接收一个旧的状态和一个 action,返回一个新的状态。
我们可以使用 Redux 的 createStore 方法来创建一个 store:
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);rootReducer 是一个将多个 reducer 合并成一个 reducer 的函数。我们可以使用 combineReducers 方法来合并多个 reducer:
// www.javascriptcn.com code example
import { combineReducers } from 'redux';
import todosReducer from './todosReducer';
import visibilityFilterReducer from './visibilityFilterReducer';
const rootReducer = combineReducers({
todos: todosReducer,
visibilityFilter: visibilityFilterReducer
});
export default rootReducer;在上面的代码中,我们将 todosReducer 和 visibilityFilterReducer 合并成一个 rootReducer。
管理应用程序的状态
在 Redux 中,我们可以使用 store.getState 方法来获取当前的应用程序状态。我们可以使用 store.dispatch 方法来分发一个 action,从而改变应用程序的状态。我们可以使用 store.subscribe 方法来监听应用程序状态的变化。
在 React Native 中,我们可以使用 react-redux 库来连接 React 组件和 Redux store。我们可以使用 connect 方法来连接一个组件和 Redux store:
// www.javascriptcn.com code example
import { connect } from 'react-redux';
const mapStateToProps = state => ({
todos: state.todos,
visibilityFilter: state.visibilityFilter
});
const mapDispatchToProps = dispatch => ({
addTodo: text => dispatch(addTodoAction(text)),
toggleTodo: id => dispatch(toggleTodoAction(id)),
setVisibilityFilter: filter => dispatch(setVisibilityFilterAction(filter))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoApp);在上面的代码中,我们将 mapStateToProps 和 mapDispatchToProps 函数作为参数传递给 connect 方法。mapStateToProps 函数将应用程序状态映射为组件的 props。mapDispatchToProps 函数将 action 创造函数映射为组件的 props。
处理异步操作
在应用程序中,我们通常需要处理异步操作,例如从服务器获取数据。在 Redux 中,我们可以使用 redux-thunk 中间件来处理异步操作。
redux-thunk 中间件允许我们将 action 创造函数返回一个函数而不是一个对象。这个函数接收 dispatch 和 getState 两个参数,可以在异步操作完成后分发一个 action。
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, applyMiddleware(thunk));在上面的代码中,我们使用 applyMiddleware 方法将 thunk 中间件添加到 store 中。
我们可以使用下面的代码来创建一个异步 action 创造函数:
// www.javascriptcn.com code example
export const fetchTodos = () => async dispatch => {
dispatch(fetchTodosRequest());
try {
const response = await fetch('https://example.com/todos');
const json = await response.json();
dispatch(fetchTodosSuccess(json));
} catch (error) {
dispatch(fetchTodosFailure(error));
}
};在上面的代码中,我们首先分发一个 fetchTodosRequest action,表示正在获取数据。然后,我们使用 fetch 方法从服务器获取数据,并将数据转换为 JSON 格式。最后,我们分发一个 fetchTodosSuccess action,表示获取数据成功,或者分发一个 fetchTodosFailure action,表示获取数据失败。
示例代码
下面是一个完整的示例代码,它演示了如何在 React Native 和 Redux 上构建可扩展的应用程序:
// www.javascriptcn.com code example
import React from 'react';
import { View, Text, TextInput, Button } from 'react-native';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { Provider, connect } from 'react-redux';
import thunk from 'redux-thunk';
// Action types
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
const FETCH_TODOS_REQUEST = 'FETCH_TODOS_REQUEST';
const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS';
const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE';
// Action creators
let nextTodoId = 0;
export const addTodoAction = text => ({
type: ADD_TODO,
id: nextTodoId++,
text
});
export const toggleTodoAction = id => ({
type: TOGGLE_TODO,
id
});
export const setVisibilityFilterAction = filter => ({
type: SET_VISIBILITY_FILTER,
filter
});
export const fetchTodosRequest = () => ({
type: FETCH_TODOS_REQUEST
});
export const fetchTodosSuccess = todos => ({
type: FETCH_TODOS_SUCCESS,
todos
});
export const fetchTodosFailure = error => ({
type: FETCH_TODOS_FAILURE,
error
});
// Reducers
const todosReducer = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
];
case TOGGLE_TODO:
return state.map(todo =>
todo.id === action.id
? { ...todo, completed: !todo.completed }
: todo
);
default:
return state;
}
};
const visibilityFilterReducer = (state = 'SHOW_ALL', action) => {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter;
default:
return state;
}
};
const todosAppReducer = combineReducers({
todos: todosReducer,
visibilityFilter: visibilityFilterReducer
});
const initialState = {
todos: [],
visibilityFilter: 'SHOW_ALL',
isFetching: false,
error: null
};
const todosAppReducerWithAsync = (state = initialState, action) => {
switch (action.type) {
case FETCH_TODOS_REQUEST:
return {
...state,
isFetching: true
};
case FETCH_TODOS_SUCCESS:
return {
...state,
isFetching: false,
todos: action.todos
};
case FETCH_TODOS_FAILURE:
return {
...state,
isFetching: false,
error: action.error
};
default:
return todosAppReducer(state, action);
}
};
// Async action creators
export const fetchTodos = () => async dispatch => {
dispatch(fetchTodosRequest());
try {
const response = await fetch('https://example.com/todos');
const json = await response.json();
dispatch(fetchTodosSuccess(json));
} catch (error) {
dispatch(fetchTodosFailure(error));
}
};
// Components
const Todo = ({ text, completed, onPress }) => (
<View>
<Text
style={{ textDecorationLine: completed ? 'line-through' : 'none' }}
onPress={onPress}
>
{text}
</Text>
</View>
);
const TodoList = ({ todos, toggleTodo }) => (
<View>
{todos.map(todo => (
<Todo
key={todo.id}
text={todo.text}
completed={todo.completed}
onPress={() => toggleTodo(todo.id)}
/>
))}
</View>
);
let AddTodo = ({ dispatch }) => {
let input;
return (
<View>
<TextInput
placeholder="Enter a todo"
onChangeText={text => (input = text)}
/>
<Button
title="Add"
onPress={() => {
dispatch(addTodoAction(input));
input = '';
}}
/>
</View>
);
};
AddTodo = connect()(AddTodo);
const Footer = ({ visibilityFilter, setVisibilityFilter }) => (
<View>
<Button
title="All"
onPress={() => setVisibilityFilter('SHOW_ALL')}
disabled={visibilityFilter === 'SHOW_ALL'}
/>
<Button
title="Active"
onPress={() => setVisibilityFilter('SHOW_ACTIVE')}
disabled={visibilityFilter === 'SHOW_ACTIVE'}
/>
<Button
title="Completed"
onPress={() => setVisibilityFilter('SHOW_COMPLETED')}
disabled={visibilityFilter === 'SHOW_COMPLETED'}
/>
</View>
);
const mapStateToProps = state => ({
todos: state.todos,
visibilityFilter: state.visibilityFilter
});
const mapDispatchToProps = dispatch => ({
toggleTodo: id => dispatch(toggleTodoAction(id)),
setVisibilityFilter: filter => dispatch(setVisibilityFilterAction(filter))
});
const TodoApp = ({ todos, visibilityFilter, toggleTodo, setVisibilityFilter }) => (
<View>
<AddTodo />
<TodoList
todos={todos.filter(todo => {
switch (visibilityFilter) {
case 'SHOW_ALL':
return true;
case 'SHOW_COMPLETED':
return todo.completed;
case 'SHOW_ACTIVE':
return !todo.completed;
}
})}
toggleTodo={toggleTodo}
/>
<Footer visibilityFilter={visibilityFilter} setVisibilityFilter={setVisibilityFilter} />
</View>
);
const store = createStore(todosAppReducerWithAsync, applyMiddleware(thunk));
const App = () => (
<Provider store={store}>
<TodoApp />
</Provider>
);
export default App;在上面的代码中,我们定义了一个 TodoApp 组件,它包含一个 AddTodo 组件、一个 TodoList 组件和一个 Footer 组件。我们使用 connect 方法将 TodoApp 组件连接到 Redux store,并将 mapStateToProps 和 mapDispatchToProps 函数作为参数传递给 connect 方法。我们使用 createStore 方法创建一个 Redux store,并将 todosAppReducerWithAsync 和 thunk 中间件作为参数传递给 createStore 方法。我们使用 Provider 组件将 TodoApp 组件包装起来,并将 Redux store 作为参数传递给 Provider 组件。我们使用 fetchTodos 异步 action 创造函数从服务器获取数据。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d918d9a941bf7134093255