【React新手学习指南】03 React脚手架实操(适合新手)

写在前面,大家好!我是【跨考菌】,一枚跨界的程序猿,专注于后台技术的输出,目标成为全栈攻城狮!这博客是对我跨界过程的总结和思考。如果你也对Java后端技术感兴趣,抑或是正在纠结于跨界,都可以关注我的动态,让我们一起学习,一起进步~
我的博客地址为:【跨考菌】的博客


上篇【React新手学习指南】02 React生命周期浅析(超详细小白也能看懂) 介绍了React面向组件编程的相关内容,包括三大属性和常见的生命周期函数的详解。本文开始学习React应用的简单上手。和【跨考菌】一起加油吧~

在这里插入图片描述

如果你觉得对你有帮助的话,记得帮博主一键三连😊哦


1 使用create-react-app创建react应用

1.1 React脚手架

  1. xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
    a. 包含了所有需要的配置
    b. 指定好了所有的依赖
    c. 可以直接安装/编译/运行一个简单效果
  2. react提供了一个用于创建react项目的脚手架库: create-react-app
  3. 项目的整体技术架构为: react + webpack + es6 + eslint
  4. 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化

1.2 创建项目流程

npm install -g create-react-app
create-react-app hello-react
cd hello-react
npm start

1.3 React脚手架项目的结构

ReactNews
	|--node_modules---第三方依赖模块文件夹
	|--public
		|-- index.html-----------------主页面
	|--scripts
		|-- build.js-------------------build打包引用配置
	|-- start.js-------------------start运行引用配置
	|--src------------源码文件夹
		|--components-----------------react组件
		|--index.js-------------------应用入口js
	|--.gitignore------git版本管制忽略的配置
	|--package.json----应用包配置文件 
	|--README.md-------应用描述说明的readme文件

2 案例一(动态评论)

2.1 效果

在这里插入图片描述

2.2 拆分组件

应用组件: App

  • state: comments/array

添加评论组件: CommentAdd

  • state: username/string, content/string
  • props: add/func

评论列表组件: CommentList

  • props: comments/array, delete/func

评论项组件: CommentItem

  • props: comment/object, delete/func, index/number

2.3 实现

app.jsx

import React from 'react'
import CommentAdd from '../comment-add/comment-add'
import CommentList from '../comment-list/comment-list'

class App extends React.Component {

  constructor (props) {
    super(props)

    this.state = {
      comments: []
    }

    this.delete = this.delete.bind(this)
  }

  componentDidMount () {
    //模拟异步获取数据
    setTimeout(() => {
      const comments = [
        {
          username: "Tom",
          content: "ReactJS好难啊!",
          id: Date.now()
        },
        {
          username: "JACK",
          content: "ReactJS还不错!",
          id: Date.now() + 1
        }
      ]
      this.setState({
        comments
      })
    }, 1000)
  }

  add = (comment) => {
    let comments = this.state.comments
    comments.unshift(comment)
    this.setState({ comments })
  }

  delete (index) {
    let comments = this.state.comments
    comments.splice(index, 1)
    this.setState({ comments })
  }

  render () {
    return (
      <div>
        <header className="site-header jumbotron">
          <div className="container">
            <div className="row">
              <div className="col-xs-12">
                <h1>请发表对React的评论</h1>
              </div>
            </div>
          </div>
        </header>
        <div className="container">
          <CommentAdd add={this.add}/>
          <CommentList comments={this.state.comments} delete={this.delete}/>
        </div>
      </div>
    )
  }
}

export default App

comment-add.jsx:

import React from 'react'
import PropTypes from 'prop-types'

class CommentAdd extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            username: '',
            content: ''
        }
        this.addComment = this.addComment.bind(this)
        this.changeUsername = this.changeUsername.bind(this)
        this.changeContent = this.changeContent.bind(this)
    }

    addComment() {
        // 根据输入的数据创建评论对象
        let {username, content} = this.state
        let comment = {username, content} // 构造需要的json
        // 添加到comments中, 更新state
        this.props.add(comment)
        // 清除输入的数据
        this.setState({
            username: '',
            content: ''
        })
    }

    changeUsername(event) {
        this.setState({
            username: event.target.value
        })
    }

    changeContent(event) {
        this.setState({
            content: event.target.value
        })
    }

    render() {
        return (
            <div className="col-md-4">
                <form className="form-horizontal">
                    <div className="form-group">
                        <label>用户名</label>
                        <input type="text" className="form-control" placeholder="用户名"
                               value={this.state.username} onChange={this.changeUsername}/>
                    </div>
                    <div className="form-group">
                        <label>评论内容</label>
                        <textarea className="form-control" rows="6" placeholder="评论内容"
                                  value={this.state.content} onChange={this.changeContent}></textarea>
                    </div>
                    <div className="form-group">
                        <div className="col-sm-offset-2 col-sm-10">
                            <button type="button" className="btn btn-default pull-right" onClick={this.addComment}>提交
                            </button>
                        </div>
                    </div>
                </form>
            </div>
        )
    }
}

CommentAdd.propTypes = {
    add: PropTypes.func.isRequired
}

export default CommentAdd

comment-list.jsx:

import React from 'react'
import PropTypes from 'prop-types'
import CommentItem from '../comment-item/comment-item'
import './commentList.css'


class CommentList extends React.Component {
  constructor (props) {
    super(props)
  }

  render () {
    let comments = this.props.comments
    let display = comments.length > 0 ? 'none' : 'block'
    return (
      <div className="col-md-8">
        <h3 className="reply">评论回复:</h3>
        <h2 style={{ display: display }}>暂无评论,点击左侧添加评论!!!</h2>
        <ul className="list-group">
          {
            comments.map((comment, index) => {
              console.log(comment)
              return <CommentItem comment={comment} key={index} index={index} delete={this.props.delete}/>
            })
          }
        </ul>
      </div>
    )
  }
}
CommentList.propTypes = {
  comments: PropTypes.array.isRequired,
  delete: PropTypes.func.isRequired
}

export default CommentList

comment-item.jsx:

import React from 'react'
import PropTypes from 'prop-types'
import './commentItem.css'

class CommentItem extends React.Component {
  constructor (props) {
    super(props)
    this.deleteComment = this.deleteComment.bind(this)
  }

  deleteComment () {
    let username = this.props.comment.username
    if (window.confirm(`确定删除${username}的评论吗?`)) {
      this.props.delete(this.props.index)
    }
  }

  render () {
    let comment = this.props.comment
    return (
      <li className="list-group-item">
        <div className="handle">
          <a href="javascript:" onClick={this.deleteComment}>删除</a>
        </div>
        <p className="user"><span >{comment.username}</span><span>:</span></p>
        <p className="centence">{comment.content}</p>
      </li>
    )
  }
}
CommentItem.propTypes = {
  comment: PropTypes.object.isRequired,
  index: PropTypes.number.isRequired,
  delete: PropTypes.func.isRequired
}

export default CommentItem

3 案例二(根据关键词拉取github相关项目)

3.1 效果

在这里插入图片描述

3.2 拆分组件

App
* state: searchName/string
Search
* props: setSearchName/func
List
* props: searchName/string
* state: firstView/bool, loading/bool, users/array, errMsg/string

3.3 实现

app.jsx:

import React from 'react'
import Search from './search'
import UserList from './user-list'

export default class App extends React.Component {

  render() {
    return (
      <div className="container">
        <section className="jumbotron">
          <h3 className="jumbotron-heading">Search Github Users</h3>
        <Search/>
        </section>
        <UserList/>
      </div>
    )
  }

}

search.jsx:

/**
 * 上部的搜索模块
 */
import React, {Component} from 'react'
import PubSub from 'pubsub-js';

class Search extends Component {

  search = () => {
    var searchName = this.nameInput.value
    console.log('searchName:', searchName)
    // 子页面发送state
    PubSub.publish("searchName", searchName);
    console.log('end')
  }

  render() {
    return (
      <div>
        <input type="text" placeholder="enter the name you search"
               ref={(input => this.nameInput = input)}/>
        <button onClick={this.search}>Search</button>
      </div>
    )
  }
}

export default Search

user-list.jsx:

/**
 * 下部的用户列表模块
 */
import React from 'react'
import axios from 'axios'
import PubSub from 'pubsub-js';

class UserList extends React.Component {

  state = {
    firstView: true, // 第一次看
    loading: false, // 加载中
    users: null, // 用户集合
    error: null
  }

  async componentDidMount()  {
    PubSub.subscribe('searchName', (msg, searchName) => { // 箭头函数,等价于func定义的函数
      console.log('发送ajax请求', searchName)
      const url = `https://api.github.com/search/users?q=${searchName}`
      this.setState({ firstView: false, loading: true }) // 开始加载

      // 使用axios库
      axios.get(url)
      .then((response) => {
        console.log(response)
        this.setState({ loading: false, users: response.data.items })
      })
      .catch((error)=>{
        // debugger
        console.log('error', error.response.data.message, error.message)
        this.setState({ loading: false, error: error.message })
      })

      // try {
      //   const result = await axios.get(url)
      //   this.setState({ loading: false, users: result.data.items })
      // } catch(err) {
      //   // debugger
      //   console.log('----', err.message)
      // }
    })
  }

  render () {

    if (this.state.firstView) {
      return <h2>Enter name to search</h2>
    } else if (this.state.loading) {
      return <h2>Loading result...</h2>
    } else if (this.state.error) {
      return <h2>{this.state.error}</h2>
    } else {
      return (
        <div className="row">
          {
            this.state.users.map((user) => (
              <div className="card" key={user.html_url}>
                <a href={user.html_url} target="_blank">
                  <img src={user.avatar_url} style={{width: '100px'}} alt='user'/>
                </a>
                <p className="card-text">{user.login}</p>
              </div>
            ))
          }
        </div>
      )
    }
  }
}

export default UserList

在这里插入图片描述
如果对你有帮助,记得帮博主一键三连😊哦

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值