[React] 18 - Project: Book Worm: Auth

前言


1、故事背景

Build App with Reactcss

Project系列,主要是从实践的角度来分析需求,设计组件,设计网页。html

 

 

2、组件设计纲要

 /* implement */react

 

 

 

代码分析


1、项目配置问题

  • Eslint

.eslintrc文件采用airbnb的严格检查模式。json

package.json中添加:redux

"lint": "eslint src"

 

  • 没用的初始化默认文件

 

  • Function component

快捷键直接获得以下代码模板:api

 

  • 偷看颜色

点击后出现颜色值提取器,以下:react-router

填下以下,这里使用了 semanitic-ui。app

import React     from "react";
import PropTypes from "prop-types";

const InlineError = ({ text }) => (
  <span style={{ color: "#ae5856" }}>{text}</span>
);

# 参数检查 InlineError.propTypes = { text: PropTypes.string.isRequired }; export default InlineError;

 

 

 

2、组件设计与实现

  • BrowserRouter

(1) This requires “yarn add react-router-dom”dom

[index.js] ide

 

(2) 配置主页 HomePage

 a. 打算 导入HomePage.js,并做为路由根路径。path = "/" exact

 b. 下一步,就是实现HomePage,至少包括了login的连接按钮。

[HomePage.js]

 

(3) 实现主页 HomePage,以及其中的 Link。

[HomePage.js]

 

(4) 实现 LoginPage

这里主要是添加上对应的路由。

[App.js]

以上便实现了一个基本的路由过程。

 

为何要用exact?

以下状况下,若是匹配路由path='/page',那么会把Home也会展现出来,这就是为何要使用exact。

<Route path='/'     component={Home} />
<Route path='/page' component={Page}>

 

 

  • LoginPage

(1) semanitic-ui

Ref: https://react.semantic-ui.com/usage

安装并导入:

$ yarn add semantic-ui-react
$ yarn add semantic-ui-css

import 'semantic-ui-css/semantic.min.css';

 className的值创建在semanitic-ui上,以后须要系统学习。

 

(2) LoginForm

render 的内容,首先得到须要的 value:

const { data, errors, loading } = this.state;  

而后渲染。

<Form.Field  ={!!errors.email}>
  <label htmlFor="email">Email</label>
  <input
    type       ="email"
    id         ="email"
    name       ="email"
    placeholder="example@example.com"
    value      ={data.email}
    onChange   ={this.onChange}
  />
  {errors.email && <InlineError text={errors.email} />}     # 判断“有错误”才出现提示
</Form.Field> <Form.Field error={!!errors.password}>   <label htmlFor="password">Password</label>   <input     type ="password"     id ="password"     name ="password"     placeholder="Make it secure"     value ={data.password}     onChange ={this.onChange}   />   {errors.password && <InlineError text={errors.password} />} </Form.Field>

格式错误后出现小提示。

 

(3) onChange

  onChange = e => {
 console.log("-->name " + e.target.name) console.log("-->value " + e.target.value)
    this.setState({
      data: { ...this.state.data, [e.target.name]: e.target.value }
    });
  }

a) 若是去掉...this.state.data会报警告以下:

b) 由于我是须要先总体覆盖一次,也就是setState的第一个参数,而后再改变咱们想要改变的。

 

(4) onSubmit

首先要验证下格式;而后再提交登陆。

 validate = data => {
    const errors = {};
    if (!Validator.isEmail(data.email)) errors.email = "Invalid email";
    if (!data.password) errors.password = "Can't be blank";
    return errors;
  };

提交操做的实现,以下:

[LoginForm.js]

  onSubmit = () => {
    const errors = this.validate(this.state.data);
this.setState({ errors });
if (Object.keys(errors).length === 0) {    // 格式没问题的话 this.setState({ loading: true }); this.props.submit(this.state.data) .catch (err => this.setState({ errors: err.response.data.errors, loading: false }) ); } };

submit 真正的实现之地在外层。

[LoginPage.js]

class LoginPage extends React.Component {
  submit = data =>
    this.props.login(data).then(() => this.props.history.push("/dashboard"));
    /* 以后会调用到 ./actions/auth.js中的login */
render() { return (
<div> <h1>Login page</h1> <LoginForm submit={this.submit} /> <Link to="/forgot_password">Forgot Password?</Link> </div> ); } }

 

(5) error={!!errors.email}

双重否认表示的意义是什么? Ref: js双感叹号判断

至关于三元运算符,返回boolean值。

var ret = !!document.getElementById
等价于:

var ret = document.getElementById ? true : false;

当值是非空字符串和非零数字返回true,当值是空字符串、0或者null返回false。

var a = " ";   alert(!!a);   //true
var a = "s";   alert(!!a);   //true
var a = true;  alert(!!a);   //true
var a = 1;     alert(!!a);   //true
var a = -1;    alert(!!a);   //true
var a = -2;    alert(!!a);   //true
 
var a = 0;     alert(!!a);   //false
var a = "";    alert(!!a);   //false
var a = false; alert(!!a);   //false
var a = null;  alert(!!a);   //false

 

 

 

3、Redux的应用

Ref: Build Real Web App with React #02

  • 导入相关库

[index.js]

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route } from "react-router-dom";
import "semantic-ui-css/semantic.min.css";
import { createStore, applyMiddleware } from "redux"; import { Provider } from "react-redux"; import thunk from "redux-thunk";
import decode from "jwt-decode";
import { composeWithDevTools } from "redux-devtools-extension";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import rootReducer from "./rootReducer";
import { userLoggedIn } from "./actions/auth";
import setAuthorizationHeader from "./utils/setAuthorizationHeader";

----------------------------------------------------------------------
const store = createStore( rootReducer,          # 树!暂时先不搭建 ---> (2) composeWithDevTools(applyMiddleware(thunk))      # ---> (1) );
----------------------------------------------------------------------
if (localStorage.bookwormJWT) { const payload = decode(localStorage.bookwormJWT); const user = { token: localStorage.bookwormJWT, email: payload.email, confirmed: payload.confirmed }; setAuthorizationHeader(localStorage.bookwormJWT); store.dispatch(userLoggedIn(user)); } ReactDOM.render(
<BrowserRouter> <Providerstore={store}> <Route component={App} /> </Provider> </BrowserRouter>, document.getElementById("root") );
registerServiceWorker();

 

(1) 合并 sub-reducer。

[rootReducer.js]

import { combineReducers } from "redux";

import user  from "./reducers/user";
import books from "./reducers/books";

export default combineReducers({
  user,
  books
});

 

(2) 实时的监控Redux的状态树的Store

Ref: Redux-devTools简单的使用

 

 

  • Redux 调用 Login by  connect(...) 

10:22 / 34:47

[LoginPage.js]

import { connect } from "react-redux";
import { Link }    from "react-router-dom";
import LoginForm   from "../forms/LoginForm";
import { login }   from "../../actions/auth";

class LoginPage extends React.Component {
  submit = data =>
    this.props.login(data).then(() => this.props.history.push("/dashboard"));
--------------------------------------------------------------------------------
render() { return (
<div> <h1>Login page</h1> <LoginForm submit={this.submit} /> <Link to="/forgot_password">Forgot Password?</Link> </div> ); } }

/**
* shape 相似于包裹着几个属性的 object
*/ LoginPage.propTypes = { history: PropTypes.shape({ push: PropTypes.func.isRequired }).isRequired, login: PropTypes.func.isRequired };

/**
* login 函数就放在了 LoginPage容器 里面
*/ export default connect(null, { login })(LoginPage);

 

 

  • 实现 Login ---> Server

[actions/auth.js]

export const login = credentials => dispatch =>
  api.user.login(credentials).then(            # 真正干活的地方
user => { localStorage.bookwormJWT = user.token; setAuthorizationHeader(user.token); dispatch(userLoggedIn(user)); }
);

这里定义了动做信号。

export const userLoggedIn = user => ({
  type: USER_LOGGED_IN,
  user
});
相关文章
相关标签/搜索