React基础知识梳理(含案例和讲解)

React基础知识梳理(含案例和讲解)

1,react 是什么?

React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。(官方明确说react不是框架,被人称为框架,可能是他真的足够强大吧。。)

  • 声明式:为状态设计UI
  • 组件化:就是一个个“零件”(即组件), 用这些零件拼凑成需要的“成品”(即UI
  • 随时随地: 不管用什么技术栈,随时随地都可以用react编写。

点击进入 👉 React中文官方文档

2,react能做啥?

做页面的UI交互。

3,怎么用react?
  • 方法一:在HTML的script标签引入React,好处是引入后能马上开始写react代码,不需要做其他引入了。适合新手。但是缺点是不适合大型 项目。所以不推荐。

  • 方法二:用react的脚手架: create-react-app

    ​ 分两种安装方法:

    • npm install -g create-react-app //安装react脚手架

      create-react-app 文件名 //创建react文件

      cd 文件名 //进入react文件

      npm start //启动项目

    • 官方文档推荐方法npx create-react-app 文件名
      cd 文件名
      npm start

4,上面的脚手架都装了啥玩意儿?

先来看看react文件里都有啥→
在这里插入图片描述

逐个说明:

  • node_modules文件夹:学过node都知道,这是存放node下载模块的,我们下载的node模块都存到这里面了
  • public文件夹:这是存放了公共资源的文件夹。html主页模板,logo图标等等.
  • src文件夹:存放自己写的代码等一些静态资源。js,css,img等。
    需要注意的是,index.js是默认的要渲染的文件。也就是说,当用npm start启动项目时,就会启动index.js里面的内容了。
5,代码写好了,该怎么让别人都能登陆浏览我编写的网站呢?

打包项目 npm run build 把开发环境中写好的代码,转成生产环境,生成一个build文件夹。把这个文件夹的内容,放到服务器根目录,网站就可以让别人看到了。

6,怎么开始写react代码呢?

还记得存放我们自己写的代码的文件夹吗? 没错,就是src文件夹

进入该文件夹。找到默认渲染的index.js文件,用编辑器打开。

把里面的ReactDOM.render(...)的这一段代码,改写成下面这样:

ReactDOM.render(
  <h1>Hello World!</h1>,
  document.getElementById('root')
);

然后在创建的react文件夹里,打开cmd控制台,输入 npm start

就会自动进入到http://localhost:3000/,页面中渲染出了这样的内容:
在这里插入图片描述
第一段react代码,就写成了!!!

7,JSX简介

什么是JSX???

再回头看一下上面的代码,<h1>Hello World!</h1>,

是不是很奇怪?JS里面怎么有HTML标签?!

没错,JS里面可以写HTML标签,这种形式,就是JSX了。

JSX既不是字符串,也不是HTML。它就是一种JS里面写HTML标签的语法。

这里还可以这样赋值。const element = <h1>Hello World!</h1>

在JSX里,还可以用{ } ,声明变量或者引入表达式。{ }里可以放任何JS表达式。

比如<h1>hello, 张{1 + 2}</h1>,输出结果就是hello, 张3

还可以这样,const name = '张三'

<h1>hello {name}</h1>

输出结果就是hello 张三

注意:JSX里的class类属性,要写成className

看完这些,肯定还是对JSX一脸懵逼的。

但是不用着急,后续还会用到大量的JSX,用多了,肯定会爱不释手的!

8,元素渲染

元素,是构成React应用的最小单位。

元素,描述了你在屏幕上想看到的内容

比如 const element = <h1>Hello, World!</h1>这就是要给元素,Hello, World!就是通过ReactDOM在页面上要渲染出来的内容了。

想要渲染出元素内容,只需要把元素放入ReactDOM.render()里即可。

ReactDOM.render(
  <h1>Hello World!</h1>, //这里就是要渲染的元素 
    //注意,这里的逗号,别忘了!!!
  document.getElementById('root')
);

元素,是不可变的普通对象。它代表了某个特定时刻的UI

9,组件

组件,类似于JS函数。但是组件的函数名首字母要大写。(小写就是函数,大写就是组件)

组件,是一块独立的代码。需要时,直接调用渲染即可。

组件,有两种标准写法:

第一种,函数形式的,例如:

function Welcome() {
    return (
    	<h1>Hello world!</h1>
    )
}
ReactDOM.render(
	<Welcome />,
    document.getElementById('root')
)

第二种,类形式的,例如:

class Welcome extends React.Component {
    render() {
        return (
        	<h1>Hello World!</h1>
        )
    }
}
ReactDOM.render(
	<Welcome />,
    document.getElementById('root')
)

以上两种写法,是等效的。

两个例子,是两种标准格式。也就是说,不管你要用哪个形式,要渲染什么内容,这个写法都不会变的。

注意,组件的 函数名和类名 的首字母要大写

10,带参数(props)的组件

组件里可以携带参数,但是组件的参数是唯一的,即props

在组件里用参数,就用props。 别无选择。

先说函数组件的设置参数和传递参数,举个例子

function Welcome(props) {
    return <h1>Hello, {props.name}</h1>
}
const name = '迪丽热巴!'
ReactDOM.render(
	<Welcome name={name}/>,
    document.getElementById('root')
)

输出结果: Hello, 迪丽热巴!

这个name 通过组件的name={name}赋值, 传给了props参数。

这里,我们打印一下props,看下props里面有什么。

function Welcome(props) {
    console.log(props)
    return <h1>Hello, {props.name}</h1>
}
const name = '迪丽热巴!'

打印结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UfxWVU7C-1595528626313)(C:\Users\Shinelon\AppData\Roaming\Typora\typora-user-images\image-20200721103637339.png)]

结果显示,props是一个对象,对象里有属性name。就是下面这样:

props = {
    name: '迪丽热巴'
}

也就是说,通过 <Welcome name={name}/>语句, name的值以对象的形式传给了props。

类组件的参数及传递

先看个例子:****

class Welcome extends React.Component {
  render() {
    console.log(this.props)
    return <h1>Hello, {this.props.name}</h1>
  }
}
const name = '迪丽热巴'
ReactDOM.render(
  <Welcome name={name} />,
  document.getElementById('root')
)
输出结果:
Hello, 迪丽热巴

这里的this.props = {
    name: '迪丽热巴'
}

通过例子可以看出,两种组件都有同样的传递参数的形式。

值得注意的是:在调用props参数的时候,函数组件是props.name,而类组件是this.props.name 。类组件是有this的。

而且,props是只读的,不可以被修改的。所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

11,组合组件

顾名思义,就是可以把多个组件组合在一起,然后渲染出结果。

直白点说,就是把多个组件,放在一个顶层组件里,然后对顶层组件进行渲染。

举个例子:

function Welcome(props) {
return <h1>Hello, {props.name}</h1>
}
function Name() { //顶层组件
  return (
    <div> //注意,这些组件都必须包含在一个顶层标签里,不然会报错
      <Welcome name='迪丽热巴!' /> //组件1
      <Welcome name='古力娜扎!' /> //组件2
      <Welcome name='巴拉巴拉!' /> //组件3
      <Welcome name='奥利给啊!' /> //组件4
    </div>
  )
}
ReactDOM.render(
  <Name />,
  document.getElementById('root')
)

输出结果:
Hello, 迪丽热巴!
Hello, 古力娜扎!
Hello, 巴拉巴拉!
Hello, 奥利给啊!
12,State

本篇开头提到了React的声明特性,就是为状态写UI。这个状态,就是state。

比如,人在站立的时候是一种站立状态,人在蹲下的时候,就是一种蹲下的状态。

我现在看时钟是1点钟是一种状态,一个小时后,看时钟是2点钟又是一种状态。

状态,就是处于某一点或某一时刻的数据。

举个例子:

function Clock(props) {
  return (
    <h1>现在的时间是: {props.date.toLocaleString()}</h1>
  )
}
ReactDOM.render(
  <Clock date={new Date()} />,
  document.getElementById('root')
)

输出结果:
现在的时间是: 2020/7/21 下午2:10:53
如果刷新页面,这个时间会随时变化。这个变化,也就是状态的变化。

如果要在代码中显示出state,就需要用到类组件了。

注意:construtor里面是唯一可以初始化状态的地方。

class Clock extends React.Component {
  constructor(props) {
    super(props) 
    this.state = { //这里是设置状态,给状态做初始化
      date: new Date()
    }
  }
  render() {
    return (
    <h1>现在的时间是: {this.state.date.toLocaleString()}</h1>
    )
  }
}
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
)

输出结果也是这个状态的时间,刷新页面,时间就会变化,也就是状态也在变化。
13,设置状态 setState()

​ 元素从一个状态,到另外一个状态,要怎么调整呢?

状态,是不能直接修改的。

但是,状态可以通过setState()来设置为新的状态。

setState()要放在函数中

class Clock extends React.Component {
  constructor(props) {
    super(props) 
    this.state = {
      date: new Date().toLocaleString()
    }
  }
  change = () => { //这里用来改变时间状态
    this.setState({
      date: new Date().toLocaleString()
    })
  }
  render() {
    return (
    <h1>现在的时间是: {this.state.date}</h1>
    )
  }
}
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
)

现在,状态已经改变了。但是页面还没有自动跟着改变状态。

那么,怎么让状态自动从一个状态到另一个状态呢?

14,生命周期–从一个状态到另一个状态,只改变状态部分,不重新渲染整个组件

假如我们不需要刷新页面,就可以从一个状态调整到另一个状态

那就要用到定时器了。但是我们又希望 在用定时器的时候,能让定时器只改变时间状态,

而不是让整个组件都重新加载

那么 我们就要用到生命周期了。

我们把13条中的代码修改一下:

class Clock extends React.Component {
  constructor(props) {
    super(props) 
    this.state = {
      date: new Date().toLocaleString()
    }
  }
  componentDidMount() { //挂载计时器
    this.timer = setInterval(this.change, 1000)
  }
  componentWillUnmount() { //卸载计时器
    clearInterval(this.timer)
  }
  change = () => { //设置状态
    this.setState({
      date: new Date().toLocaleString()
    })
  }
  render() {
    return (
    <h1>现在的时间是: {this.state.date}</h1> //被渲染的元素
    )
  }
}
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
)

挂载当前状态 → 卸载改变后的状态 ,这就是一个生命周期。

15,事件处理

React元素的事件处理和DOM元素的很相似,但是语法上有点不同:

  • React事件命名用驼峰命名,而不是纯小写
  • 使用JSX语法时,传入的是一个函数作为事件处理函数,而不是传入一个字符串

例如,传统的HTML:

<button οnclick="activateLasers()">
	点击
</button>

在React中略微不同:

<button onClick={activateLasers}>
	点击
</button>
  • 阻止默认行为,也有所不同。
    传统的HTML阻止链接默认打开一个新页面:

    <a href="#" οnclick="console.log('The link was clicked')"; return false>
    	Click me
    </a>
    

    在React可能是这样的:

    handleClick = (e) => {
        e.preventDefault()
        console.log('The link was clicked.')
    }
    

事件处理案例:点击按钮 在ON和OFF之间来回切换

class ToggleBtn extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isChanging: true
    }
  }
  handleClick = () => { // 这里如果不用箭头函数,就在constructor里绑定this
    this.setState({
      isChanging: !this.state.isChanging //修改状态
    })
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isChanging ? 'ON' : 'OFF'} //开关切换的三元表达式
      </button>
    )
  }
}
ReactDOM.render(
  <ToggleBtn />, //渲染这个组件
  document.getElementById('root')
)

16,条件渲染

在React中,你可以创建不同的组件来封装各种你需要的行为。然后,依据应用的不同状态,你可以只渲染对应状态下的部分内容

使用条件语句 if ,条件运算符(也叫三元运算符), &&, || ,!等。

举例,根据不同条件,来让组件1或者组件2来运行:

function Com1() { // 组件1
  return (
    <h1>这是组件1在执行--</h1>
  )
}
function Com2() { // 组件2
  return (
    <h1>这是组件2在执行--</h1>
  )
}
function Run(props) {
  const isRunning = props.isRunning // 定义变量
  if (isRunning) { //判断条件
    return <Com1 />
  }
  return <Com2 />
}
ReactDOM.render(
  <Run isRunning={true}/>,
  document.getElementById('root')
)

17,列表&&key

这里说的列表,是根据数组元素,生成相应的列表标签。

map()函数来完成

使用{}在JSX里构建一个元素集合

举例:

const numbers = [1, 2, 3, 4, 5] //给出一个数组
const listItems = numbers.map( //用map()函数对数组内每个元素进行遍历
  (number) => <li>{number}</li> //把遍历的元素放入li标签
)
ReactDOM.render(
  <ul>{listItems}</ul>, //渲染时 把li标签放入ul标签
  document.getElementById('root')
)

输出结果:
在这里插入图片描述
在运行这段代码时,会看到一串警告:
在这里插入图片描述
意思是,在列表里的每一个子元素都必须有一个key参数。

怎么给子元素设置key参数呢?如下:

const listItems = numbers.map((number) =>
    <li key={number.toString()}> //在这里给子元素设置key参数
      {number}
    </li>
  )
18,关于key参数

key是用来帮助react识别是哪些元素改变了,比如被添加了或者被删除了。

key是这个元素在列表中拥有独一无二的字符串

应该在哪里设置key值呢?

记住:在 map() 方法中的元素需要设置 key 属性

key会传递信息给react,但是不会传递给你写的组件。

19,表单(input, textarea, select)–受控组件

表单有输入和提交的状态,状态保存在state属性中,state成为唯一数据源。

渲染表单的React组件还控制着用户输入过程中表单发生的操作。被React以这种方式控制取值的表单输入元素就叫做“受控组件

案例:提交输入的内容,并弹窗提示提交了什么内容

class InputCom extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      value: ''
    }
  }
  handleChange=(e)=> {
    this.setState({
      value: e.target.value //输入的内容
    })
  }
  handleSubmit=(e)=> {
    alert('提交的内容是: ' + this.state.value)
    // e.preventDefault() //阻止提交刷新页面
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}> {/*提交事件*/}
        <label>
          <input type="text" value={this.state.value} 
          onChange={this.handleChange} /> {/*输入事件*/}
        </label>
        <input type="submit" value="提交" />
      </form>
    )
  }
}
ReactDOM.render(
  <InputCom />,
  document.getElementById('root')
)

试运行结果:
在这里插入图片描述
input, textarea, select三者非常类似。

值得一提的是,select中的selected属性。 在React中 并不会使用selected属性,而是在根select标签上使用value属性。

20,表单(input type=“file”)–非受控组件

既然有受控组件,那就一定有对应的非受控组件。

这里先挖个坑,后续写项目用到了,回来补。

21,状态提升

通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。这就叫“状态提升

个人觉得官方文档中给的案例看着有点费劲儿,就自己写了一个长度间的转换案例,如下:

let dataTitle = {
  m: '输入米数: ',
  cm: '输入厘米数: '
}

//抽离出来的输入框组件
class LengthData extends React.Component {
  render() {
    let title = this.props.title
    let input = this.props.input
    let onChange = this.props.onChange
    let data = this.props.data
    return (
      <fieldset>
        <legend>{title}</legend>
        <input type="text" value={data} 
          onChange={onChange} />
      </fieldset>
    )
  }
}

//编写实现输入框的组件
class Length extends React.Component { 
  constructor(props) {
    super(props) 
      //状态提升
    this.state = {
      type: '',
      input: ''
    }
  }
  checkedInput(input) {
    // console.log(typeof(input))
    if (Number.isNaN(input) || parseFloat(input) < 0) {
      alert ('输入数据有误,重新输入!')
      this.setState({
        type: '',
        input: ''
      })
    } 
    return input
  }
  convertCM(input) {
    return input * 100
  }
  convertM(input) {
    return input / 100
  }
  handleChange=(type, e) => {
    if (type === 'meter') {
      this.setState({
        type: 'meter',
        input: e.target.value
      })
    }else if (type === 'centimeter') {
      this.setState({
        type: 'centimeter',
        input: e.target.value
      })
    }
  }
  render() {
      //meter centimeter type data 这些都是为实现交互而设置的变量
    let input = this.state.input
    let type = this.state.type
    let meter = type === 'centimeter' ? this.convertM(this.checkedInput(input)) : input
    let centimeter = type === 'meter' ? this.convertCM(this.checkedInput(input)) : input
    return (
      <div>
        <h3>长度单位转换</h3>
        <LengthData title={dataTitle.m} data={meter}
        onChange={(e)=> {this.handleChange('meter' ,e)}} />
        <LengthData title={dataTitle.cm} data={centimeter}
        onChange={(e)=> {this.handleChange('centimeter' ,e)}} />
      </div>
    )
  }
}
ReactDOM.render(
  <Length />,
  document.getElementById('root')
)

**第一步:**编写实现输入框的组件(这一步在代码案例中看着不是很明显了)

**第二步:**抽离输入框组件(方便写入多个输入框)

**第三步:**状态提升(把子组件中的状态拿走,状态都放在父组件中)

**第四步:**状态交互 (核心代码,也是最难理解的一段代码)

**第五步:**调试bug(输入和输出结果的调试,比如输入不符合要求,给错误提示,然后清空输入框,阻止交互)

22,组合与继承的对比

官方文档说明:巧用组合,慎用继承

组合在实际敲代码的过程中,非常容易用到,且我们在学习的过程中,已经用过多次。

举例说明:

function App1() {
  return (
    <h1>Hello, React!</h1>
  )
}
function App2() {
  return (
    <h1>你好,react!</h1>
  )
}
function App3() {
  return (
    <div>
      <App1 />
      <h3>翻译如下:</h3>
      <App2 />
    </div> 
  )
}
ReactDOM.render(
  <App3 />,
  document.getElementById('root')
)

// 该案例就是把通过App3 把组件App1和App2组合在一起,通过render渲染出来。

输出结果:
在这里插入图片描述

23, Thinking In React
  • 用react思想构建快速响应的大型web应用程序。

  • 写网页时,最好先写静态页面,再写交互UI。两者分开写。

  • 因为静态页面代码多,细节少。 交互UI是代码少,细节多。(参照第21条给出的案例)

  • React是基于state的改变来实现UI交互的。所以,用好state。

  • 习惯写组件,避免重复代码。

  • 用props和state不止可以从父组件到子组件传输数据,还可以实现从子组件到父组件的数据传输。

看来了这里,恭喜你,你已经是React的基础用户了!

赶紧写个项目练练手吧!

后续我会把React的进阶知识整理出来,发到博客。

-----------------------------End-------------------------------
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值