React-初识详解(长篇幅详细)

前言: 什么是React?这里是React初识。

npx create-react-app “项目名”

react用到的第三方包

  • classnames

  • styled-components 将css独立来写的第三方包

  • prop-types:props的类型检测工具

  • axios
    在jsx里面写js代码就加一个{}

  • 创建一个简单的react:

          import React from "react"
          import ReactDOM from "react-dom"
          // const app = <h1>welcome first!</h1> // jsx语法,不需要加引号
          const createApp = (props) => {
              return (
                  <div>
                      {/* {只要在jsx里面写js代码就要加一层花括号注释也要用花括号} */}
                      <h1>欢迎来到{props.title}</h1>
                      <p>优秀的{props.title}</p>
                  </div>
              )
          }
          const app = createApp({
              title: '德莱联盟'
          })
          ReactDOM.render(
              app,
              document.querySelector("#root")
          )
    

react定义组件的方式:

  1. 箭头函数,组件的首字母大写
  2. 使用类组件,可以嵌套
  • <1> 箭头函数方法:

          // react创建组件的第一个方式:箭头函数,这个名字要大写 App
          const App = (props) => {
              return (
                  <div>
                      <h1 title={props.title}>想吃很多{props.title}</h1>
                      <p>有很多{props.title}</p>
                  </div>
              )
          }
          ReactDOM.render(
              <App title="炸鸡腿"/>,
              document.querySelector("#root")
          )
    
  • <2>使用类继承React.Component:

          // 定义组件的第二个方法:使用类继承React.Component
          import React, { Component } from "react"
          import { render } from "react-dom"
      
          class App extends Component {
              render () {
                  console.log(this.props) //{title: "类组件是继承React.Component的"}  参数传递就用this.props
                  return (
                      <div>
                          <h1>类组件</h1>
                          <p>{this.props.title}</p>
                      </div>
                  )
              }
          }
          // render 是ReactDOM提供的方法,这个方法通常只会使用一次
          render(
              <App title="类组件是继承React.Component的"/>,
              document.querySelector("#root")
          )
      
          // 16版本以前创建组件的方法
          // React.createClass({
          //     render () {
          //         return (
          //             <div>{this.props.title}</div>
          //         )
          //     }
          // })
    

组件嵌套

import React, { Component } from "react"
import { render } from "react-dom"

const Header = () => <h1>组件嵌套</h1>
class App extends Component {
    render () {
        return (
            <div>
                <Header />
                <p>{this.props.title}</p>
            </div>
        )
    }
}

render(
    <App title="react组件可以嵌套"/>,
    document.querySelector("#root")
)
  • jsx原理,通过React.createElement的方式创建元素,有无限个参数,但前两个是固定的,第一个标签名,第二个是标签的属性,剩下的都是子元素
    React.createElement(type,[props],[…children])

          import React, { Component } from "react"
          import { render } from "react-dom"
          class App extends Component {
              render () {
                  return (
                      React.createElement (
                          'div',
                          {
                              className: 'app',
                              id: 'appRoot'
                          },
                          React.createElement (
                              'h1',
                              {
                                  className: 'title'
                              },
                              'jsx原理'
                          ),
                          React.createElement (
                              'p',
                              null,
                              'jax到底怎么写?'
                          )
                      )
                  )
              }
          }
      
          // const appVDom = {
          //     tag: "div",
          //     attrs: {
          //         className: "app",
          //         id: "appRoot"
          //     },
          //     children: [
          //         {
          //             tag: "h1",
          //             attrs: {
          //                 className: "app"
          //             },
          //             children: [
          //                 "jsx原理"
          //             ]
          //         }, {
          //             tag: "p",
          //             attrs: null,
          //             children: [
          //                 "jsx到底怎么写呢?"
          //             ]
          //         }
          //     ]
      
          // }
      
          render(
              <App />,
              document.querySelector("#root")
          )
    

react里的css

  1. 使用style标签内联创建

         import React, { Component } from "react"
         import { render } from "react-dom"
         import classNames from "classnames"
         import styled from "styled-components"
         import './index.css'
     
         const Title = styled.h2`
             color: #f00
             `
     
         class App extends Component {
             render () {
                 const style = {color: '#f00'}
                 return (
                     <div>
                         <h1>元素的样式</h1>
                         <Title>styled-components的使用</Title>
                         <ol>
                             <li style={style}>使用style方式</li>
                             <li className='redclass'>使用class方式,但在react里要写成className</li>
                             <li className={classNames('a',{'b': true,'c': false})}>要动态添加className使用classnames第三方包</li>// 该li的class只有a,b没有c
                         </ol>
                     </div>
                 )
             }
         }
     
         render(
             <App />,
             document.querySelector("#root")
         )
    
  2. 使用class方式,但是要写成className,样式写在css文件中,所有要先import引入
    第三方的css包:1、classnames,可以动态添加不同的className

  3. styled-components 将css独立来写的第三方包

React项目组件化

快捷键:rcc react的class component;rfc react的function component

  1. 整个单页应用的入口文件:App.js

  2. 入口文件:index.js

  3. 其余的子组件包在App下面

  4. 在src下新建一个components目录,里面包含所有的子组件,一个子组件就是一个文件夹,用组件名作为文件夹名字;同时,在components的根目录下还有一个index.js文件,用来引入和导出所有的子组件,在App.js里面引入所有的组件。

  1. 在src下创建一个services文件夹,里面有apis.js和index.js文件。apis.js是统一管理接口的文件
组件化开发React todolist, 项目开发中的组件的基本目录结构基本上是这样的:
> /your-project
>
> - src
>   - …
>   - components
>     - YourComponentOne
>       - index.js/YourComponentOne.js
>     - YourComponentTwo
>       - index.js/YourComponentTwo.js
>     - index.js 用于导出组件
注意:一个组件只干一件事情 ,所以TodoList和TodoItem要做成两个组件,这样也方便于后期理解shouldComponentUpdate
  • 一个组件里的return只能有一个根元素 ,因此react里可以使用Fragment(需要import引入,是一个空标签),或者直接使用空标签

          import React, { Component, Fragment } from 'react'
          import {
              TodoHeader,
              TodoInput,
              TodoList
          } from './components'
          export default class App extends Component {
            render() {
              return (
                <Fragment>
                  <TodoHeader />
                  <TodoInput />
                  <TodoList />
                </Fragment>
      
              //   <>
              //     <TodoHeader />
              //     <TodoInput />
              //     <TodoList />
              //   </>
              )
            }
          }
    

两种导出方式:

//第一种,当需要对这里引入的组件进行处理再导出时使用
// import TodoHeader from './TodoHeader'
// import TodoInput from './TodoInput'
// import TodoList from './TodoList'

// export {
//     TodoHeader,
//     TodoInput,
//     TodoList
// }

//第二种
export { default as TodoHeader} from './TodoHeader'
export { default as TodoInput} from './TodoInput'
export { default as TodoList} from './TodoList'

组件的数据挂载方式

  1. 通过props传递
    function组件直接通过props.xxx,class组件通过this.props.xxx传递

         import React from 'react'
     
         export default function TodoHeader(props) {
           console.log(props)// {title: "待办事项"}
           return (
             <h1>
               {props.title}
             </h1>
           )
         }
    

属性(props)

props.children 组件标签内的内容

// App.js
export default class App extends Component {
  render() {
    return (
      <Fragment>
        <TodoHeader desc="完成今天所有的事">
          待办事项列表
        </TodoHeader>
        <TodoInput btnText="ADD"/>
        <TodoList />
      </Fragment>

// TodoHeader/index.js
export default function TodoHeader(props) {
  console.log(props) // {desc: "完成今天所有的事", children: "待办事项列表"}
  return (
    <h1>
      {props.children}
    </h1>
  )
}
  • prop-types:props的类型检测工具

          // TodoHeader/index.js
          import React from 'react'
          import PropTypes from 'prop-types'
          export default function TodoHeader(props) {
            console.log(props)
            return (
              <>
                <h1>
                  {props.children}
                </h1>
                <h3>{props.desc}</h3>
                <p>{props.x + props.y}</p>
              </>
            )
          }
          TodoHeader.propTypes = {
            desc: PropTypes.string,
            x: PropTypes.number.isRequired,
            y: PropTypes.number.isRequired
          }
    
  • class组件写法:

          // TodoInput.js
          import React, { Component } from 'react'
          import PropTypes from 'prop-types'
          export default class TodoInput extends Component {
            static propTypes = {
              btnText: PropTypes.string
            }
            static defaultProps = {
              btnText: '添加TODO' //组件默认值
            }
          //TodoHeader.defaultProps = {
          //  desc: '如果能重来'
          //}  //funciton组件写法
            render() {
              return (
                <div>
                  <input type="text"/><button>{this.props.btnText}</button>
                </div>
              )
            }
          }
    

state

组件内部状态定义用state,有两种定义方法 ,而props是外部传入的属性.只有class组件才有this和state

// App.js
export default class App extends Component {
// 第一张定义方式
//  state = {
//    title: '待办事项'
//  }
// 第二种定义方法
  constructor () {
    super()
    this.state = {
      title: '待办事项',
      desc: '完成今天所有的事'
    }
  }
  render() {
    return (
      <Fragment>
        <TodoHeader desc={this.state.desc}>
          {this.state.title}
        </TodoHeader>

组件的分类:

  • class组件和function组件

  • 受控组件、不受控组件、半受控组件(通过props传入属性,在组件内部没法修改的叫受控组件,通过state定义的状态不是外部传入的时不受控组件)

  • 不能跨组件传递props,必须一层一层的传

  • 组件模板渲染语法

    {/* {this.todos[0].isCompleted && '完成'} */}
    {this.state.todos[0].isCompleted ? '完成' : '未完成'}
            {
              this.state.todos.map(todo => {
                return <div key={todo.id}>{todo.title}</div>
              })
            }
    
    {div dangerouslySetInnerHTML={{__html: this.state.article}}} // 渲染不带HTML标签的内容
    

dangerouslySetInnerHTML,类似于vue的v-html,输出不带HTML标签的内容

属性vs状态

  • 相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)

  • 不同点:

1.属性能从父组件获取,状态不能
2.属性可以由父组件修改,状态不能
3.属性能在内部设置默认值,状态也可以
4.属性不在组件内部修改,状态要改
5.属性能设置子组件初始值,状态不可以
6.属性可以修改子组件的值,状态不可以

  • state 的主要作用是用于组件保存、控制、修改自己的可变状态。state 在组件内1部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState方法进行更新,setState 会导致组件的重新渲染。

  • props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。

  • 如果搞不清 state 和 props 的使用场景,记住一个简单的规则:尽量少地用 state,多用 props。

  • 没有 state 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。

更改状态(setState)

  • react不能直接通过this.state.xxx = !this.state.xxx来直接更改状态,要用setSate()方法来更改。(能修改数据,但是页面不会渲染)

  • setState()有两个参数,第一个参数有两种情况:第一种是一个对象;第二种情况是一个方法。

  • setState的第二个参数是一个回调在里面return一个对象,由于setState是异步的,想要获取最新的state要在第二个参数的回调里获取

  • react的setState是异步的,setState里的方法要比它外面的方法后执行

      import React, { Component } from 'react'
    
      export default class Like extends Component {
          constructor () {
              super()
              this.state = {
                  isLiked: false
              }
          }
          likedClick = () => {
              // setState的第一种写法
              // this.setState({
              //     isLiked: !this.state.isLiked
              // })
              // 第二种写法是一个方法,可以直接传上次的状态prevState和props
              this.setState((prevState) => {
                  console.log(prevState)
                  return {
                      isLiked: !prevState.isLiked
                  }
              }, () => {
                  // setState是异步的,想要获取最新的state要在这个回调里获取
                  console.log(this.state)
              })
          }
        render() {
          return (
          ·
           	 <div>
              <span onClick={this.likedClick}>
                  {
                      this.state.isLiked ? '太菜了!👍' : '棒棒哒!👎'
                  }
              </span>
            </div>
          )
        }
      }
    

react事件

如果要修改state里的值需要使用onChange事件(这是采用驼峰命名的),然后通过setState方法来修改值,否则页面上不能输入

// TodoInput/index.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class TodoInput extends Component {
  static propTypes = {
    btnText: PropTypes.string
  }
  static defaultProps = {
    btnText: '添加TODO'
  }
  constructor () {
    super()
    this.state = {
      inputValue: 'xxx'
    }
    // this.addTodo = this.addTodo.bind(this)
  }
  onInputChange = (e) => {
    this.setState({
      inputValue: e.currentTarget.value
    })
  }
addTodo = (id) => {
  console.log(this.state,id)
  }
  render() {
    return (
      <div>
        <input type="text" onChange={this.onInputChange} value={this.state.inputValue}/>
        <button onClick={this.addTodo.bind(this,1234)}>{this.props.btnText}</button>
      </div>
    )
  }
}
// App.js
addItem = (todoTitle) => {
    console.log(todoTitle)
    // this.setState({
    //   // 添加todo的第一个方法,这里不能用push,push返回的是数组的长度
    //   todos: this.state.todos.concat({
    //     id: Math.random(),
    //     title: todoTitle,
    //     isCompleted: false
    //   })
    // })
    // 第二个方法,先把数组复制一份
    // const newTodos = this.state.todos.slice()
      const newTodos = [...this.state.todos]
    newTodos.push({
        id: Math.random(),
        title: todoTitle,
        isCompleted: false
    })
    this.setState({
      todos: newTodos
    })
  }

react里面通过ref获取组件或者dom元素,在使用ref之前要先调用React.createRef来创建ref,要在constructor里创建ref。

import React, { Component, createRef } from 'react'
import PropTypes from 'prop-types'
export default class TodoInput extends Component {
  static propTypes = {
    btnText: PropTypes.string
  }
  static defaultProps = {
    btnText: '添加TODO'
  }
  constructor () {
    super()
    this.state = {
      inputValue: ''
    }
    // this.addTodo = this.addTodo.bind(this)
    // 在constructor里创建ref
    this.inputDom = createRef()
  }
  onInputChange = (e) => {
    this.setState({
      inputValue: e.currentTarget.value
    })
  }
  addKeyUp = (e) => {
    if(e.keyCode === 13){
      // console.log(e)
      this.addTodo()
    }
  }
  addTodo = () => {
    if(this.state.inputValue === ''){
      return
    }
    console.log(this.inputDom)
    this.props.addItem(this.state.inputValue)
    this.setState({
      inputValue: ''
    }, () => {
        this.inputDom.current.focus()
    })
  }
  render() {
    return (
      <div>
        <input type="text" onChange={this.onInputChange} onKeyUp={this.addKeyUp} value={this.state.inputValue} ref={this.inputDom}/>
        <button onClick={this.addTodo}>{this.props.btnText}</button>
      </div>
    )
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值