【React全家桶入门之八】用户编辑与删除

来源:互联网 发布:罗盘酒店软件价格 编辑:程序博客网 时间:2024/06/04 18:49

前文中实现了用户添加与用户列表展示的功能,本篇带大家来完成用户的编辑与删除。

添加操作列

编辑与删除功能都是针对已存在的某一个用户执行的操作,所以在用户列表中需要再加一个“操作”列来展现【编辑】与【删除】这两个按钮。

修改/src/pages/UserList.js文件,添加方法handleEdit与handleDel,并在table中添加一列:

...class UserList extends React.Component {  constructor (props) { ... }  componentWillMount () { ... }  handleEdit (user) {  }  handleDel (user) {  }  render () {    const {userList} = this.state;    return (      <HomeLayout title="用户列表">        <table>          <thead>          <tr>            <th>用户ID</th>            <th>用户名</th>            <th>性别</th>            <th>年龄</th>            <th>操作</th>          </tr>          </thead>          <tbody>          {            userList.map((user) => {              return (                <tr key={user.id}>                  <td>{user.id}</td>                  <td>{user.name}</td>                  <td>{user.gender}</td>                  <td>{user.age}</td>                  <td>                    <a href="javascript:void(0)" onClick={() => this.handleEdit(user)}>编辑</a>                    &nbsp;                    <a href="javascript:void(0)" onClick={() => this.handleDel(user)}>删除</a>                  </td>                </tr>              );            })          }          </tbody>        </table>      </HomeLayout>    );  }}...

点击编辑(删除)时,会把该行的user对象作为参数传给handleEdit(handleDel)方法,在handleEdit(handleDel)方法中我们就可以根据传入的user对象进行相应的操作了。

用户删除

用户删除比较简单,先解决它。

在执行删除数据的操作时,通常需要对操作进行进一步的确认以避免误删数据酿成惨剧。

所以在handleDel方法中我们应该先确认用户是否想要执行删除操作,在用户确认后调用删除用户的接口来删除用户:

  ...  handleDel (user) {    const confirmed = confirm(`确定要删除用户 ${user.name} 吗?`);    if (confirmed) {      fetch('http://localhost:3000/user/' + user.id, {        method: 'delete'      })        .then(res => res.json())        .then(res => {          this.setState({            userList: this.state.userList.filter(item => item.id !== user.id)          });          alert('删除用户成功');        })        .catch(err => {          console.error(err);          alert('删除用户失败');        });    }  }  ...

用户编辑

用户编辑和用户添加基本上是一样的,不同的地方有:

  • 用户编辑需要将用户的数据先填充到表单
  • 用户编辑在提交表单的时候调用的接口和方法不同
  • 页面标题不同
  • 页面路由不同

那么我们可以复制UserAdd.js文件的代码到一个新的UserEdit.js文件中,再对上述四点进行修改…吗?

当然不行!在前文中我们费尽心思对重复代码进行优化,更不能为了偷懒直接复制代码完事啦。

想办法让原来的代码既能够支持添加操作又能够支持编辑操作!

为了达到这一个目标,我们需要:

  • 升级formProvider使其返回的表单组件支持传入表单的值(用于主动填充表单)
  • 将UserAdd.js中的大部分代码抽离到一个通用组件UserEditor,通过传入不同的props来控制组件的行为是添加还是编辑

升级formProvider

修改/src/utils/formProvider.js文件:

function formProvider (fields) {  return function (Comp) {    ...    class FormComponent extends React.Component {      constructor (props) {        ...        this.setFormValues = this.setFormValues.bind(this);      }      setFormValues (values) {        if (!values) {          return;        }        const {form} = this.state;        let newForm = {...form};        for (const field in form) {          if (form.hasOwnProperty(field)) {            if (typeof values[field] !== 'undefined') {              newForm[field] = {...newForm[field], value: values[field]};            }            // 正常情况下主动设置的每个字段一定是有效的            newForm[field].valid = true;          }        }        this.setState({form: newForm});      }      handleValueChange (fieldName, value) { ... }      render () {        const {form, formValid} = this.state;        return (          <Comp             {...this.props}            form={form}            formValid={formValid}            onFormChange={this.handleValueChange}            setFormValues={this.setFormValues}          />        );      }    }    return FormComponent;  }}...

给表单组件传入了一个setFormValues的方法,用于在组件中主动设置表单的值。

抽离UserEditor

接下来新建/src/components/UserEditor.js文件,将表单处理代码从UserAdd.js里搬过去(省略号部分与原来的代码相同):

import React from 'react';import FormItem from '../components/FormItem';import formProvider from '../utils/formProvider';class UserEditor extends React.Component {  handleSubmit (e) { ... }  render () {    const {form: {name, age, gender}, onFormChange} = this.props;    return (      <form onSubmit={(e) => this.handleSubmit(e)}>        ...      </form>    );  }}UserEditor.contextTypes = {  router: React.PropTypes.object.isRequired};UserEditor = formProvider({ ... })(UserEditor);export default UserEditor;

然后再handleSubmit方法中,通过检查是否收到一个editTarget的props来判断这次的操作是添加操作还是编辑操作,并根据当前的操作切换调用接口的url和method:

  ...  handleSubmit (e) {    e.preventDefault();    const {form: {name, age, gender}, formValid, editTarget} = this.props;    if (!formValid) {      alert('请填写正确的信息后重试');      return;    }    let editType = '添加';    let apiUrl = 'http://localhost:3000/user';    let method = 'post';    if (editTarget) {      editType = '编辑';      apiUrl += '/' + editTarget.id;      method = 'put';    }    fetch(apiUrl, {      method,      body: JSON.stringify({        name: name.value,        age: age.value,        gender: gender.value      }),      headers: {        'Content-Type': 'application/json'      }    })      .then((res) => res.json())      .then((res) => {        if (res.id) {          alert(editType + '用户成功');          this.context.router.push('/user/list');          return;        } else {          alert(editType + '失败');        }      })      .catch((err) => console.error(err));  }  ...

同时,我们也需要在UserEditor加载的时候检查是否存在props.editTarget,如果存在,使用props.setFormValues方法将editTarget的值设置到表单:

  ...  componentWillMount () {    const {editTarget, setFormValues} = this.props;    if (editTarget) {      setFormValues(editTarget);    }  }  ...

这样我们的UserEditor就基本完成了,当我们要作为一个用户添加器使用时,只需要:

  ...  <UserEditor/>  ...

而作为一个用户编辑器使用时,则需要将编辑的目标用户对象传给editTarget这个属性:

  ...  <UserEditor editTarget={user}/>  ...

所以现在就可以将UserAdd.js文件改成这样了:

import React from 'react';import HomeLayout from '../layouts/HomeLayout';import UserEditor from '../components/UserEditor';class UserAdd extends React.Component {  render () {    return (      <HomeLayout title="添加用户">        <UserEditor/>      </HomeLayout>    );  }}export default UserAdd;

添加UserEditPage

现在需要添加一个/src/pages/UserEdit.js文件作为编辑用户的页面:

import React from 'react';import HomeLayout from '../layouts/HomeLayout';import UserEditor from '../components/UserEditor';class UserEdit extends React.Component {  constructor (props) {    super(props);    this.state = {      user: null    };  }  componentWillMount () {    const userId = this.context.router.params.id;    fetch('http://localhost:3000/user/' + userId)      .then(res => res.json())      .then(res => {        this.setState({          user: res        });      });  }  render () {    const {user} = this.state;    return (      <HomeLayout title="编辑用户">        {          user ? <UserEditor editTarget={user}/> : '加载中...'        }      </HomeLayout>    );  }}UserEdit.contextTypes = {  router: React.PropTypes.object.isRequired};export default UserEdit;

在这个页面组件里,我们根据路由中名为id的参数(this.context.router.params.id)来调用接口获取用户数据(保存在this.state.user中)。

当user数据未就绪时,我们不应该展示出编辑器以避免用户混乱或者误操作:使用三元运算符,当this.state.user有值时渲染UserEditor组件,否则显示文本“加载中…”。

注意:任何使用this.context.xxx的地方,必须在组件的contextTypes里定义对应的PropTypes。

别忘了在/src/index.js中给页面添加路由,路由的path中使用:id来定义路由的参数(参数名与页面组件中获取参数时的参数名相对应):

import UserEditPage from './pages/UserEdit';ReactDOM.render((  <Router history={hashHistory}>    ...    <Route path="/user/edit/:id" component={UserEditPage}/>  </Router>), document.getElementById('app'));

完成handleEdit方法

最后,来补上UserList页面组件的handleEdit方法:

class UserList extends React.Component {  constructor (props) { ... }  componentWillMount () { ... }  handleEdit (user) {    this.context.router.push('/user/edit/' + user.id);  }  handleDel (user) { ... }UserList.contextTypes = {  router: React.PropTypes.object.isRequired};

在handleEdit方法中只需要使用router.push方法跳转到该用户的编辑页面,别忘了加上contextTypes。

看看效果:

此处输入图片的描述

大功告成!

1 0
原创粉丝点击