昨天介紹了如何使用 React Native 的 Modal 來實作一個確認刪除的提示 Modal,今天要做的則是如何使用 Modal 來編輯原本的待辦事項。
為了支援待辦事項的編輯功能,首先需要在 context store 中加入一些新的狀態值以及對應的 action 處理方法。
首先,在 initialState
中加入 modalVisible
中的 edit
和 editText
兩個新的狀態。其中,edit
用於控制編輯 Modal 的顯示狀態,而 editText
則用於儲存目前的編輯內容。
// src/store/index.js:
const initialState = {
inputText: '',
todos: [],
modalVisible: {
confirm: false,
edit: false
},
chooseId: null,
editText: ''
}
接著,我們在 reducer
中加入幾個新的 action
處理還有修正原本的:
editText
為該待辦事項的內容。這三個 action handlers 的實現如下:
case 'SET_CHOOSE_ID':
return {
...state,
chooseId: action.payload,
editText: state.todos.find((todo) => todo.id === action.payload).text
}
case 'EDIT_ITEM':
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.payload.id
? { ...todo, text: action.payload.text }
: todo
)
}
case 'SET_EDIT_TEXT':
return {
...state,
editText: action.payload
}
有了上面的準備,接下來可以開始新增一個 EditModal
元件,用於顯示編輯界面。
這個元件主要包含以下部分:
TextInput
用於輸入和編輯待辦事項的內容。元件的程式碼如下:
import { useContext } from 'react'
import {
Modal,
View,
Text,
TouchableOpacity,
TextInput,
StyleSheet
} from 'react-native'
import { Store } from '../store'
const EditModal = () => {
const { state, dispatch } = useContext(Store)
const { modalVisible, chooseId, editText } = state
const closeModel = () => {
dispatch({
type: 'SET_MODAL_VISIBLE',
payload: { name: 'edit', visible: false }
})
}
const handleSetText = (text) => {
dispatch({ type: 'SET_EDIT_TEXT', payload: text })
}
const handleConfirmEdit = () => {
dispatch({ type: 'EDIT_ITEM', payload: { id: chooseId, text: editText } })
closeModel()
}
return (
<View style={styles.container}>
<Modal
animationType='fade'
transparent={true}
visible={modalVisible.edit}
onRequestClose={closeModel}
>
<View style={styles.container}>
<View style={styles.modalWrap}>
<TextInput
value={state.editText}
onChangeText={handleSetText}
autoCapitalize='none'
placeholder='請輸入事項'
style={styles.input}
/>
<View style={styles.buttons}>
<TouchableOpacity
onPress={closeModel}
style={[styles.button, { backgroundColor: '#f66162' }]}
>
<Text style={{ color: '#fff' }}>取消修改</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={handleConfirmEdit}
style={[styles.button, { backgroundColor: '#a1f64c' }]}
>
<Text>確定修改</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0,0,0,0.5)'
},
modalWrap: {
paddingHorizontal: 15,
paddingTop: 50,
paddingBottom: 30,
borderRadius: 10,
backgroundColor: '#fff',
width: '95%'
},
buttons: {
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
marginTop: 40
},
button: {
padding: 10,
borderRadius: 5
},
input: {
borderColor: '#bcb9b9',
borderWidth: 1,
borderRadius: 5,
paddingHorizontal: 15,
fontSize: 20,
backgroundColor: '#fff',
height: 50
}
})
export default EditModal
最後,我們需要在 App.js
中導入並使用這個新增的 EditModal
元件。
import EditModal from './src/components/EditModal'
export default function App() {
return (
<StoreProvider>
<RootSiblingParent>
<SafeAreaView style={styles.container}>
<Head />
<List />
<ConfirmModal />
<EditModal />
<StatusBar style='auto' />
</SafeAreaView>
</RootSiblingParent>
</StoreProvider>
)
}
編輯功能的觸發點在於待辦事項列表,所以我們需要在 List
元件中加入相應的控制邏輯。
首先,我們定義一個 handleEditText
的函式,它接受一個待辦事項 ID 作為參數。當使用者想要編輯一個待辦事項時,我們首先使用 SET_CHOOSE_ID
來設定當前選擇的待辦事項ID,然後打開 EditModal
。
const handleEditText = (id) => {
dispatch({ type: 'SET_CHOOSE_ID', payload: id })
dispatch({ type: 'SET_MODAL_VISIBLE', payload: { name: 'edit', visible: true } })
}
並在 <Item />
新增一個 onEditText
props 並將 handleEditText
帶入。
const renderItem = ({ item }) => (
<Item
item={item}
onToggleItem={() => handleToggleItem(item.id)}
onConfirmDelete={() => handleConfirmDelete(item.id)}
onEditText={() => handleEditText(item.id)}
/>
)
此外,我們還需要在每個待辦事項的呈現中,綁定這個 handleEditText
到對應的操作上,這裡我們設定在點擊文字的行為上。
const Item = ({ item, onToggleItem, onConfirmDelete, onEditText }) => (
<View style={styles.item}>
<View style={styles.checkboxAndText}>
<Checkbox
value={item.checked}
onValueChange={onToggleItem}
color={item.checked && '#1dee98'}
/>
<Text onPress={onEditText} style={[styles.itemText, item.checked && styles.finishItemText]}>
{item.text}
</Text>
</View>
<TouchableOpacity onPress={onConfirmDelete}>
<MaterialCommunityIcons name='delete-circle' size={24} color='#ED6070' />
</TouchableOpacity>
</View>
)
今天我們新增了一個 Modal,並且用它來編輯待辦事項,其實跟昨天的刪除提示 Modal 蠻像的,只是編輯所需要掌握的狀態控制更多了一點。
下一篇文章,將會示範如何將待辦事項保存到本地儲存,即使 App 被關閉或者重啟後,待辦事項的內容仍然可以被保留。