官术网_书友最值得收藏!

Save button

In this section, we will create a button in the upper-right corner of the navigation bar that is labeled as Save. When it is tapped on, the following two things must happen:

  • The changes the user made to the to-do item (such as its name, completion status, and due date) must be saved to AsyncStorage, overwriting its previous details
  • The TasksList must be updated so that the user visually sees the changes they made right away

Rendering the Save button is easy with React Native. The object that gets pushed to NavigatorIOS needs to receive the following two key/value pairs:

  • rightButtonTitle: This is a string that renders the text shown in that area
  • onRightButtonPress: This is a callback that is fired when that button is pressed

At face value, this looks simple. However, we can't pass any information to the onRightButtonPress method of NavigatorIOS from a rendered child. Instead, we have to keep a copy of the changes we make inside our TasksList component as well, and update them as the DatePickerIOS, TextInput, and Switch components within EditTask are updated.

// Tasks/app/components/TasksList/index.js 

...
export default class TasksList extends Component {
constructor (props) {
...
this.state = {
currentEditedTaskObject: undefined,
...
};
}
...
_completeTask (rowID) {
const singleUpdatedTask = {
...this.state.listOfTasks[rowID],
completed: !this.state.listOfTasks[rowID].completed
};

this._saveAndUpdateSelectedTask(singleUpdatedTask, rowID);
}

This is no longer an asynchronous function. The part of the function that took advantage of async/await is broken off into _saveAndUpdateSelectedTask.

Set the currently edited task object to state:

  _editTask (rowData, rowID) { 
this.setState({
currentEditedTaskObject: rowData
});

Add an onRightButtonPress callback and string for the right button's title:

    this.props.navigator.push({ 
...
onRightButtonPress: () => this._saveCurrentEditedTask(rowID),
rightButtonTitle: 'Save',

Pass in four new functions to EditTask that deal with the item's details:

      passProps: { 
changeTaskCompletionStatus: (status) =>
this._updateCurrentEditedTaskObject('completed', status),
changeTaskDueDate: (date, formattedDate) =>
this._updateCurrentEditedTaskDueDate
(date, formattedDate),
changeTaskName: (name) =>
this._updateCurrentEditedTaskObject('text', name),
clearTaskDueDate: () =>
this._updateCurrentEditedTaskDueDate(undefined, undefined),
}
});
}

Add arguments for _editTask to accept:

  _renderRowData (rowData, rowID) { 
return (
<TasksListCell
...
onLongPress={ () => this._editTask(rowData, rowID) }
...
/>
)
}

This is the logic previously found in componentDidMount. It was broken into its own function since _saveCurrentEditedTask needs to call it:

  async _saveAndUpdateSelectedTask (newTaskObject, rowID) { 
const listOfTasks = this.state.listOfTasks.slice();
listOfTasks[rowID] = newTaskObject;

await AsyncStorage.setItem('listOfTasks',
JSON.stringify(listOfTasks));

this._updateList();
}

To save the current edited task, we pass the object and rowID to _saveAndUpdateSelectedtask, and then call pop on the navigator:

_saveCurrentEditedTask (rowID) { 
this._saveAndUpdateSelectedTask(this.state.currentEditedTaskObject,
rowID);
this.props.navigator.pop();
}

This function updates the date and formattedDate of the current edited task object:

  _updateCurrentEditedTaskDueDate (date, formattedDate) { 
this._updateCurrentEditedTaskObject ('due', date);
this._updateCurrentEditedTaskObject ('formattedDate',
formattedDate);
}

The following function accepts a key and value, creates a clone of currentEditedTaskObject with the new value, and sets it in state:

  _updateCurrentEditedTaskObject (key, value) { 
let newTaskObject = Object.assign({},
this.state.currentEditedTaskObject);

newTaskObject[key] = value;

this.setState({
currentEditedTaskObject: newTaskObject
});
}
...
}

The last two functions' purpose is to update the TasksList local state copy of the object being edited. This is done for two reasons:

  • Any updates we make to EditTask, such as changing the name, completion status, and due date, currently do not propagate up to its parent
  • Additionally, we can't just point the values in EditTask to what gets passed in as props since the EditTask component does not rerender whenever the props being passed to it change

EditTask gets a couple of changes including new propTypes for the component to expect:

// Tasks/app/components/EditTask/index.js 

...
export default class EditTask extends Component {
static propTypes = {
changeTaskCompletionStatus: PropTypes.func.isRequired,
changeTaskDueDate: PropTypes.func.isRequired,
changeTaskName: PropTypes.func.isRequired,
clearTaskDueDate: PropTypes.func.isRequired,
...
}

The changes that EditTask receives involve calling the functions that are passed to it as props to update the parent component's data for saving:

  ... 
render () {
...
const dueDateSetTitle = 'Due On ' +
this.state.formattedDate || this.props.formattedDate;
...
}

_changeTextInputValue (text) {
...
this.props.changeTaskName(text);
}

_clearDate () {
...
this.props.clearTaskDueDate();
}
...
_onDateChange (date) {
...
this.props.changeTaskDueDate(date, formattedDate);
}
...
_onSwitchToggle (completed) {
...
this.props.changeTaskCompletionStatus(completed);
}
}
主站蜘蛛池模板: 孟津县| 徐汇区| 百色市| 高邑县| 安仁县| 阳曲县| 平江县| 金山区| 灯塔市| 西和县| 亚东县| 屏东县| 九台市| 克东县| 文山县| 西贡区| 扬州市| 克什克腾旗| 缙云县| 高要市| 隆回县| 阳泉市| 纳雍县| 沈丘县| 新竹县| 土默特右旗| 汶上县| 罗城| 定陶县| 丹阳市| 岢岚县| 嘉定区| 儋州市| 弥渡县| 武城县| 博兴县| 山阳县| 江孜县| 同德县| 长葛市| 湖北省|