4
头图

join us!

160f6828a44399 " , to provide front-end developers with technical information and a series of basic articles. For a better user experience, please move to our official website novices (160f6828a443a1 https://xhs-rookies.com/ ) to learn and get the latest articles in time.

"Code tailor" , if you are interested in our article or want to make some suggestions, follow "Novices of Xiaohe Mountain" public account, contact us, you can also watch it on WeChat Our article. Every suggestion or approval is a great encouragement to us!

Practical case (four): perfecting the message board login

We learned some new content this time, and we need to revise the previous version.

First we need the login page and HOC (high-level component). Add routing jumps to improve the page.

Add routing

yarn add react-router-dom

Let's join react-router

Modify routing configuration

We need to modify index.js , before index.js has been only App.js a, we add routes configuration to index.js in.

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Switch>
        <Route path="/login" component={Login} />
        <Route path="/home" component={App} />
        <Redirect path="/" to="/login" exact />
      </Switch>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root'),
)

By default, we let the page point to the Login page.

Login page

Login status maintenance

If we log in successfully, we should need a place to store the information about whether the login is successful or not, in preparation for the subsequent authentication, we use localstorage for data persistence processing.

this.props.history.replace('/home')
window.localStorage.islogin = '1'

Authentication jump

We need to authenticate on the login page. We let the login page judge when the loading is complete. If you have already logged in, then we will jump to the home homepage. Here we use the componentDidMount() method in the react component life cycle. Make judgments.

  componentDidMount() {
    let localStorage = window.localStorage
    if (localStorage.islogin === '1') {
      this.props.history.replace("/home")
    }
  }

Final combination

class Login extends PureComponent {
  componentDidMount() {
    let localStorage = window.localStorage
    if (localStorage.islogin === '1') {
      this.props.history.replace('/home')
    }
  }

  constructor(props) {
    super(props)
    this.state = {
      username: '',
      password: '',
    }
  }

  render() {
    return (
      <div className="login">
        <h2>欢迎来到XXX博客区</h2>
        <form className="form">
          <div className="formItem">
            <label htmlFor="username">用户名:</label>
            <input
              type="text"
              id="username"
              value={this.state.username}
              onChange={(e) => {
                this.setState({ username: e.target.value })
              }}
            />
          </div>
          <div className="formItem">
            <label htmlFor="password">密码:</label>
            <input
              type="password"
              id="password"
              value={this.state.password}
              onChange={(e) => {
                this.setState({ password: e.target.value })
              }}
            />
          </div>
          <div
            className="loginBtn"
            onClick={() => {
              this.handleLogin()
            }}
          >
            登录
          </div>
        </form>
      </div>
    )
  }

  handleLogin() {
    if (this.state.username && this.state.password) {
      this.props.history.replace('/home')
      window.localStorage.islogin = '1'
      alert('欢迎!')
    } else {
      alert('请输入用户名和密码!')
    }
  }
}

export default Login

does not require components

Last time we InputCompoent input box component and EvaluateCompoent list display component and placed them in the component folder. We first placed these two components directly in App.js .

We only need to abstract a comment component, add our like function to the last EvaluateCompoent list display component, and we can like each comment in the list.

Therefore, we App.js as follows:

import React, { PureComponent } from 'react'
import Comment from './comment'
import './App.css'

class App extends PureComponent {
  constructor() {
    super()
    this.state = {
      title: 'Hello React',
      desc: '你知道有这么一个团队吗?他们怀揣梦想,艰苦奋斗,作为一群大学生菜鸟,放弃了平时娱乐的时间,选择一起学习,一起成长,将平时学习的笔记,心得总结为文章,目的很简单,希望可以帮助向他们一样的菜鸟们?你想了解更多吗?快搜索微信公众号:小和山的菜鸟们,加入他们吧!',
      comments: [
        {
          headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
          time: new Date(2021, 4, 14, 21, 2, 30),
          nickName: '小菜鸟',
          detail: '这是一个即将推出系列文章的团队,我们一起期待他们的作品吧!',
          liked: true,
          likeNum: 23,
        },
      ],
      text: '',
    }
  }

  render() {
    const { title, desc, comments, text } = this.state
    return (
      <div className="App">
        <h2>{title}</h2>
        <div className="desc">{desc}</div>
        <div style={{ width: '100%' }}>
          <p className="commentsTitle">评论</p>
          {comments.map((item, index) => {
            return (
              <Comment
                key={item.time.getTime()}
                changeLike={() => {
                  this.changeLike(index)
                }}
                {...item}
              />
            )
          })}
        </div>

        <div className="newComment">
          <div style={{ display: 'flex' }}>
            <img src="https://xhs-rookies.com/img/rookie-icon.png" className="" alt="" />
            <textarea value={text} onChange={(e) => this.changeText(e)} placeholder="请输入评论" />
          </div>

          <div
            className="submit"
            onClick={() => {
              this.addComment()
            }}
          >
            发表
          </div>
        </div>
      </div>
    )
  }

  changeText(e) {
    this.setState({ text: e.target.value })
  }

  changeLike(index) {
    let newArray = [...this.state.comments]
    let newItem = { ...newArray[index] }
    if (newItem.liked) {
      newItem.liked = false
      newItem.likeNum -= 1
    } else {
      newItem.liked = true
      newItem.likeNum += 1
    }
    newArray[index] = newItem
    this.setState({
      comments: newArray,
    })
  }

  addComment() {
    if (!this.state.text) {
      alert('请输入留言内容')
      return
    }
    let detail = this.state.text
    this.setState({ text: '' })
    let newComment = {
      headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
      time: new Date(),
      nickName: '小菜鸟',
      detail,
      liked: false,
      likeNum: 0,
    }
    this.setState({
      comments: [newComment, ...this.state.comments],
    })
  }
}

App.propTypes = {}

export default App

Home page modification

Homepage authentication

Here we also need authentication, that is, if you enter home directly in the browser, if you are not logged in, we need to make it jump to the login login page.

Can we use the same time as logging in, after the loading is completed, judge and then jump?

  componentDidMount() {
    let localStorage = window.localStorage
    if (localStorage.islogin === '1') {
      this.props.history.replace("/home")
    }
  }

In fact, there is a problem here. If we jump directly after the loading is completed, do we have to join every page?

But this authentication is actually a general function. If there is still a personal information page now, does it also need such a function?

High-level component authentication

We use high-level components for authentication, so if each page needs to be authenticated in the future, it only needs to be wrapped by high-level components.

import React from 'react'
import { Redirect } from 'react-router-dom'

export default function checkRole(WrapperComponent) {
  let localStorage = window.localStorage
  return (props) => {
    if (localStorage.islogin === '1') {
      return <WrapperComponent {...props} />
    } else {
      return <Redirect to="/" />
    }
  }
}

Then we Home homepage ( App.js )

export default checkRole(App)

Logout options

After we log in successfully, then we naturally need to add a logout option on the main page. After logging out, and entering the main page again, we will be authenticated and jump to the login page.

  handleLogout() {
    window.localStorage.islogin = '0'
    this.props.history.replace("/login")
  }

The final main page is as follows:

import React, { PureComponent } from 'react'
import Comment from './comment'
import checkRole from './checkRole'
import './App.css'

class App extends PureComponent {
  constructor() {
    super()
    this.state = {
      title: 'Hello React',
      desc: '你知道有这么一个团队吗?他们怀揣梦想,艰苦奋斗,作为一群大学生菜鸟,放弃了平时娱乐的时间,选择一起学习,一起成长,将平时学习的笔记,心得总结为文章,目的很简单,希望可以帮助向他们一样的菜鸟们?你想了解更多吗?快搜索微信公众号:小和山的菜鸟们,加入他们吧!',
      comments: [
        {
          headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
          time: new Date(2021, 4, 14, 21, 2, 30),
          nickName: '小菜鸟',
          detail: '这是一个即将推出系列文章的团队,我们一起期待他们的作品吧!',
          liked: true,
          likeNum: 23,
        },
      ],
      text: '',
    }
  }

  render() {
    const { title, desc, comments, text } = this.state
    return (
      <div className="App">
        <span
          className="logout"
          onClick={() => {
            this.handleLogout()
          }}
        >
          退出登录
        </span>
        <h2>{title}</h2>
        <div className="desc">{desc}</div>
        <div style={{ width: '100%' }}>
          <p className="commentsTitle">评论</p>
          {comments.map((item, index) => {
            return (
              <Comment
                key={item.time.getTime()}
                changeLike={() => {
                  this.changeLike(index)
                }}
                {...item}
              />
            )
          })}
        </div>

        <div className="newComment">
          <div style={{ display: 'flex' }}>
            <img src="https://xhs-rookies.com/img/rookie-icon.png" className="" alt="" />
            <textarea value={text} onChange={(e) => this.changeText(e)} placeholder="请输入评论" />
          </div>

          <div
            className="submit"
            onClick={() => {
              this.addComment()
            }}
          >
            发表
          </div>
        </div>
      </div>
    )
  }

  handleLogout() {
    window.localStorage.islogin = '0'
    this.props.history.replace('/login')
  }

  changeText(e) {
    this.setState({ text: e.target.value })
  }

  changeLike(index) {
    let newArray = [...this.state.comments]
    let newItem = { ...newArray[index] }
    if (newItem.liked) {
      newItem.liked = false
      newItem.likeNum -= 1
    } else {
      newItem.liked = true
      newItem.likeNum += 1
    }
    newArray[index] = newItem
    this.setState({
      comments: newArray,
    })
  }

  addComment() {
    if (!this.state.text) {
      alert('请输入留言内容')
      return
    }
    let detail = this.state.text
    this.setState({ text: '' })
    let newComment = {
      headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
      time: new Date(),
      nickName: '小菜鸟',
      detail,
      liked: false,
      likeNum: 0,
    }
    this.setState({
      comments: [newComment, ...this.state.comments],
    })
  }
}

App.propTypes = {}

export default checkRole(App)

to sum up

At this point, our entire React actual combat case is over. Although it is a simple message case, it contains a lot of knowledge points, from the beginning HTML to the scaffolding creation.

Added home page authentication, use PropTypes check whether the incoming data meets the requirements, and use HOC (high-end components) to add general component functions.

Direct preview

We recommend using codesanbox to quickly access current actual cases online.

CodeSandBox

Preview of the next section

At this point, we React . In the next section, we will move to a higher mountain- Hooks , so stay tuned!


小和山的菜鸟们
377 声望2.1k 粉丝

每日进步的菜鸟,分享前端学习手册,和有心学习前端技术的小伙伴们互相探讨,一同成长。