React project actual combat rental app project (9) login module basic layout and function realization

foreword

1. Housing details module

The housing details module is mainly to display the housing information obtained before. Since the function is relatively simple, I won’t go into details here.

2. Login module

2.1 Effect diagram of login module

insert image description here

2.2 Basic layout

Add the following code in src/pages/Login/index.js:

<div className={
    
    styles.root}>
  {
    
    /* 顶部导航 */}
  <NavHeader className={
    
    styles.navHeader}>账号登录</NavHeader>
  <WhiteSpace size="xl" />

  {
    
    /* 登录表单 */}
  <WingBlank>
    <form>
      <div className={
    
    styles.formItem}>
        <input
          className={
    
    styles.input}
          name="username"
          placeholder="请输入账号"
        />
      </div>
      <div className={
    
    styles.formItem}>
        <input
          className={
    
    styles.input}
          name="password"
          type="password"
          placeholder="请输入密码"
        />
      </div>
      <div className={
    
    styles.formSubmit}>
        <button className={
    
    styles.submit} type="submit">
          登 录
        </button>
      </div>
    </form>
    <Flex className={
    
    styles.backHome}>
      <Flex.Item>
        <Link to="/registe">还没有账号,去注册~</Link>
      </Flex.Item>
    </Flex>
  </WingBlank>
</div>

2.3 Call the interface to realize login

Implementation steps:

1、添加状态:username和password
2、使用受控组件方式获取表单元素值
3、给form表单添加onSubmit
4、创建方法 handleSubmit,实现表单提交
5、在方法中,通过username和password获取到账号和密码
6、使用API调用登录接口,将username和password作为参数
7、判断返回值status为200时候,表示登录成功
8、登录成功后,将token保存到本地存储中(hkzf_token)
9、返回登录前的页面

Code example:
Add the following code in src/pages/Login/index.js:

  state = {
    
    
    username: '',
    password: ''
  }

getUserName = e => {
    
    
  this.setState({
    
    
    username: e.target.value
  })
}

getPassword = e => {
    
    
  this.setState({
    
    
    password: e.target.value
  })
}

// 表单提交事件的事件处理程序
handleSubmit = async e => {
    
    
  // 阻止表单提交时的默认行为
  e.preventDefault()
  // 获取账号和密码
  const {
    
     username, password } = this.state

  // 发送请求
  const res = await API.post('/user/login', {
    
    
    username,
    password
  })
  const {
    
     status, body, description } = res.data
  if (status === 200) {
    
    
    // 登录成功
    localStorage.setItem('hkzf_token', body.token)
    this.props.history.go(-1)
  } else {
    
    
    // 登录失败
    Toast.info(description, 2, null, false)
  }
}

render() {
    
    
    const {
    
     username, password } = this.state

    return (
      <div className={
    
    styles.root}>
        ...

        {
    
    /* 登录表单 */}
        <WingBlank>
          <form onSubmit={
    
    this.handleSubmit}>
            <div className={
    
    styles.formItem}>
              <input
                className={
    
    styles.input}
                value={
    
    username}
                onChange={
    
    this.getUserName}
                name="username"
                placeholder="请输入账号"
              />
            </div>

            <div className={
    
    styles.formItem}>
              <input
                className={
    
    styles.input}
                value={
    
    password}
                onChange={
    
    this.getPassword}
                name="password"
                type="password"
                placeholder="请输入密码"
              />
            </div>
            ...
      </div>
    )
  }
}

2.4 Realize the form verification function

2.4.1 formik introduction

1、使用场景:表单处理,表单验证
2、优势:轻松处理React中的复杂表单,包括:获取表单元素的值,表单验证和错误信息,处理表单提交,并且将这些内容放在一起统一处理,有利于代码阅读,重构,测试等
3、使用方式:1. 高阶组件(withFormik) 2. render-props(<Formik render={
    
    () => {
    
    }} />

2.4.2 Basic use of formik

Steps for usage:

1、安装: yarn add formik
2、导入 withFormik,使用withFormit 高阶组件包裹Login组件
3、为withFormit提供配置对象: mapPropsToValues / handleSubmit
4、在Login组件中,通过props获取到values(表单元素值对象),handleSubmit,handleChange
5、使用values提供的值,设置为表单元素的value,使用handleChange设置为表单元素的onChange
6、使用handleSubmit设置为表单的onSubmit
7、在handleSubmit中,通过values获取到表单元素值
8、在handleSubmit中,完成登录逻辑

Code example:
Add the following code in src/pages/Login/index.js:

class Login extends Component {
    
    

  render() {
    
    
    // 通过 props 获取高阶组件传递进来的属性
    const {
    
     values, handleSubmit, handleChange } = this.props

    return (
      <div className={
    
    styles.root}>
        {
    
    /* 顶部导航 */}
        <NavHeader className={
    
    styles.navHeader}>账号登录</NavHeader>
        <WhiteSpace size="xl" />

        {
    
    /* 登录表单 */}
        <WingBlank>
          <form onSubmit={
    
    handleSubmit}>
            <div className={
    
    styles.formItem}>
              <input
                className={
    
    styles.input}
                value={
    
    values.username}
                onChange={
    
    handleChange}
                name="username"
                placeholder="请输入账号"
              />
            </div>
            <div className={
    
    styles.formItem}>
              <input
                className={
    
    styles.input}
                value={
    
    values.password}
                onChange={
    
    handleChange}
                name="password"
                type="password"
                placeholder="请输入密码"
              />
            </div>
            <div className={
    
    styles.formSubmit}>
              <button className={
    
    styles.submit} type="submit">
                登 录
              </button>
            </div>
          </form>
          <Flex className={
    
    styles.backHome}>
            <Flex.Item>
              <Link to="/registe">还没有账号,去注册~</Link>
            </Flex.Item>
          </Flex>
        </WingBlank>
      </div>
    )
  }
}

// 使用 withFormik 高阶组件包装 Login 组件,为 Login 组件提供属性和方法
Login = withFormik({
    
    
  // 提供状态:
  mapPropsToValues: () => ({
    
     username: '', password: '' }),
  // 表单的提交事件
  handleSubmit: async (values, {
     
      props }) => {
    
    
    // 获取账号和密码
    const {
    
     username, password } = values

    // 发送请求
    const res = await API.post('/user/login', {
    
    
      username,
      password
    })

    const {
    
     status, body, description } = res.data

    if (status === 200) {
    
    
      // 登录成功
      localStorage.setItem('hkzf_token', body.token)

      // 注意:无法在该方法中,通过 this 来获取到路由信息
      // 所以,需要通过 第二个对象参数中获取到 props 来使用 props
      props.history.go(-1)
    } else {
    
    
      // 登录失败
      Toast.info(description, 2, null, false)
    }
  }
})(Login)


// 注意:此处返回的是 高阶组件 包装后的组件
export default Login

2.4.3 Add form validation

Implementation steps:

1、安装Yup: yarn add yup 
2、在项目中导入Yup
3、在 withFormik 中添加配置项 validationSchema,使用 Yup 添加表单校验规则
4、在 Login 组件中,通过 props 获取到 errors(错误信息)和 touched(是否访问过,注意:需要给表单元素添加 handleBlur 处理失焦点事件才生效!)
5、在表单元素中通过这两个对象展示表单校验错误信

Code example:
Add the following code in src/pages/Login/index.js:

{
    
    /* 登录表单 */}
<WingBlank>
  <form onSubmit={
    
    handleSubmit}>
    ...  用户名的错误提示
    {
    
    errors.username && touched.username && (
      <div className={
    
    styles.error}>{
    
    errors.username}</div>
    )}
    ... 密码框的错误提示
    {
    
    errors.password && touched.password && (
      <div className={
    
    styles.error}>{
    
    errors.password}</div>
    )}
    ...
</WingBlank>

// 使用 withFormik 高阶组件包装 Login 组件,为 Login 组件提供属性和方法
Login = withFormik({
    
    
  ...
  // 添加表单校验规则
  validationSchema: Yup.object().shape({
    
    
    username: Yup.string()
      .required('账号为必填项')
      .matches(REG_UNAME, '长度为5到8位,只能出现数字、字母、下划线'),
    password: Yup.string()
      .required('密码为必填项')
      .matches(REG_PWD, '长度为5到12位,只能出现数字、字母、下划线')
  }),
  ...
})(Login)

2.5 Code optimization

Optimization steps:

1、导入 Form组件,替换form元素,去掉onSubmit
2、导入Field组件,替换input表单元素,去掉onChange,onBlur,value
3、导入 ErrorMessage 组件,替换原来的错误消息逻辑代码
4、去掉所有 props

Code example:
Modify the following code in src/pages/Login/index.js:

// 导入withFormik
import {
    
     withFormik, Form, Field, ErrorMessage } from 'formik'

<Form>
  {
    
    /* 账号 */}
  <div className={
    
    styles.formItem}>
    <Field
      className={
    
    styles.input}
      name="username"
      placeholder="请输入账号"
    />
  </div>
  <ErrorMessage
    className={
    
    styles.error}
    name="username"
    component="div"
  />
  {
    
    /* 密码 */}
  <div className={
    
    styles.formItem}>
    <Field
      className={
    
    styles.input}
      name="password"
      type="password"
      placeholder="请输入密码"
    />
  </div>
  <ErrorMessage
    className={
    
    styles.error}
    name="password"
    component="div"
  />
  <div className={
    
    styles.formSubmit}>
    <button className={
    
    styles.submit} type="submit">
      登 录
    </button>
  </div>
</Form>

Summarize

Guess you like

Origin blog.csdn.net/qq_40652101/article/details/128865570