likes
comments
collection
share

React简易上手指南

作者站长头像
站长
· 阅读数 57

1.React介绍

💎 起源

React是用于构建用户界面的JavaScript库,起源于Facebook的内部项目,该公司对市场上所有 JavaScript MVC框架都不满意,决定自行开发一套,用于架设Instagram的网站。于2013年5月开源。

对市场上所有 JavaScript MVC框架都不满,决定自行开发一套。

这不禁让我联想,断水流大师兄。😎

React简易上手指南

💎 官方文档

闲话休提,言归正传。

先来附上官方文档地址,传送门点击即可穿越:

🚀官网地址

🚀中文官网地址

💎 对比Vue

ReactVue相同的地方,都是虚拟的DOM和组件化

不同于Vue的双向数据绑定React采用的是单向数据流

💎 单向数据流

React 中的数据流是单向的,并顺着组件层级从上往下传递。

2.环境搭建和HelloWorld程序

  1. 通过 React.Component 创建一个组件 HelloComponent
  2. 使用 React 最常用的方法,通过 render 将模板转为html语言
  3. 通过 ReactDOM 插入到指定的 DOM 节点,譬如 container

🎸 示例代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="container">

  </div>
  <!-- react 核心js -->
  <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
  <!-- react-dom 渲染dom的js -->
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>

  <script>
    class HelloComponent extends React.Component {
      render() {
        return React.createElement('h1', null, 'Hello World');
      }
    }
    ReactDOM.render(React.createElement(HelloComponent, null,), document.getElementById('container'))
  </script>
</body>

</html>

😜 页面显示

React简易上手指南

👺 简要说明

代码中的 React.createElement 方法,有三个参数:

  1. 第一个参数是必填,传入的是HTML标签名称,譬如: ul, li
  2. 第二个参数是选填,表示的是属性,譬如: className
  3. 第三个参数是选填, 子节点,譬如: 要显示的文本内容

开发时,通常会使用 JSX 语法,其实它最终会转化成 React.createElement 去创建元素。

3.初始JSX语法

设想如下变量声明:

const element = <h1>Hello, world!</h1>;

这个有趣的标签语法,既不是字符串也不是 HTML

它被称为 JSX,是一个 JavaScript 的语法扩展

我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。

JSX 可能会使人联想到模板语言,好像HTML,但它具有 JavaScript 的全部功能。

JSX使用的是ES6的标准,如果浏览器不支持,就需要将JSX转成普通JavaScript。

在生产中,通常使用Babel 转换,再提交到服务器。

写这个demo的时候,使用 browser.js 也就是babel核心库,在客户端转换。

譬如,可以通过如下地址,引入 browser.min.js 文件

https://unpkg.com/babel-standalone@6.15.0/babel.min.js

💊 将之前的代码,修改一下。

React.createElement('h1', null, 'Hello World');
//改为JSX的写法
<h1>Hello World</h1>
React.createElement(HelloComponent, null,)
//改为JSX的写法
<HelloComponent />

📃 完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="container">

  </div>
  <!-- react 核心js -->
  <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
  <!-- react-dom 渲染dom的js -->
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js" crossorigin></script>

  <script type="text/babel">
    class HelloComponent extends React.Component {
      render() {
        return <h1>Hello World</h1>
      }
    }
    ReactDOM.render(<HelloComponent />, document.getElementById('container'))
  </script>
</body>

</html>

🐶 页面显示

React简易上手指南

上面已经说到过,JSX 语法,其实它最终会转化成 React.createElement 去创建元素。

也就是说,可以JSX将理解为React.createElement(component, props, ...children)方法的语法糖

可以通过props传递属性参数

class HelloComponent extends React.Component {
  render() {
    return <h1>Hello { this.props.name }</h1>
  }
}
ReactDOM.render(<HelloComponent name="malena" />, document.getElementById('container'))

页面成功显示属性name的值:

React简易上手指南

🙈🙉🙊 Malena 很美

哎呀,写着写着,又跑题了。😹

正如 React 官网所说, JSX是 JavaScript 的语法扩展,它具有 JavaScript 的全部功能。

那么,当然可以在 JSX 里面写三元表达式,或者二元表达式。

但是,不支持 if 或 else 语法。

class HelloComponent extends React.Component {
  render() {
    return <h1>Hello { this.props.name ? this.props.name: 'World' }</h1>
  }
}
ReactDOM.render(<HelloComponent />, document.getElementById('container'))
class HelloComponent extends React.Component {
  render() {
    return <h1>Hello { this.props.name || 'World' }</h1>
  }
}
ReactDOM.render(<HelloComponent />, document.getElementById('container'))

4.进阶JSX语法

介绍一下 JSX 中循环的写法,其实和JavaScript一样。

let names = ['mila', 'malena', 'morgan'];
class HelloComponent extends React.Component {
  render(h) {
    return (
      <div>
        {
          names.map(name => <div key={name}> Hello, {name}</div>)
        }
      </div>
    )
  }
}
ReactDOM.render(<HelloComponent />, document.getElementById('container'))

🍜 刚才是通过JavaScript的数组,循环遍历。也可以直接写JSX进行循环。

let arr = [
  <h1>mila</h1>,
  <h1>malena</h1>,
  <h1>morgan</h1>
]
ReactDOM.render(<div>{ arr }</div>, document.getElementById('container'))

🍕 页面显示

React简易上手指南

需要注意的是,数组循环,一定要加上key值。

否则,将会看到一个警告 a key should be provided for list items

意思是当你创建一个元素时,必须包括一个特殊的 key 属性。

🎯 key

key 帮助 React 识别哪些元素改变了,比如被添加或删除。

因此你应当给数组中的每一个元素赋予一个确定的标识。

关于 列表 & Key的详情讲解,请移步官方文档:

🚀列表 & Key

5.组件state成员

React组件是React最重要的组成部分。

根据不同 state 状态,渲染不同组件。和Vue一样,都是数据驱动页面。

👒 代码示例:

class TextBoxComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      enable: false
    }
  }
  // 注意,handleClick 方法要用箭头函数
  // 因为,点击时,handleClick()方法中的this已经不是组件里的this
  // 箭头函数,使得this从正常情况下的动态作用域(根据运行位置确定值)变成了静态作用域(根据定义位置确定值,也就是词法作用域)。
  handleClick = (event) => {
    this.setState({ enable: !this.state.enable })
  }
  render(h) {
    return (
      <p>
        <input type="text" disabled={this.state.enable} />
        <button onClick={this.handleClick}>改变TextBoxComponent状态</button>
      </p>
    )
  }
}

ReactDOM.render(<TextBoxComponent />, document.getElementById("container"))

6.Props和Render

👕 props

举个例子,一个input输入框,类型type,就是props

<input type="text" /> 

React 中使用 JSX 语法,可以使用类似 HTML的写法,通过属性传入参数。

class HelloBox extends React.Component {
  render(h) {
    return (
      <div>{'Hello' + this.props.attr}</div>
    )
  }
}
ReactDOM.render(<HelloBox attr="Halo Beach" />, document.getElementById('container'))

🚤 render

render 是一个函数。

对组件来说,render在创建时,是必须的。

render 用于检测 this.statethis.props,用于返回组件实例。

在render内,不应该改变组件的state,也不和浏览器交互。

state和交互,写在生命周期和其他函数里。

render里就是最简单的,最纯粹的,组件的主体。

7.组件的生命周期

组件的生命周期可分成三个状态:

  1. Mounting(挂载):已插入真实 DOM
  2. Updating(更新):正在被重新渲染
  3. Unmounting(卸载):已移出真实 DOM

React简易上手指南

🎄 挂载

当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

1.constructor(): 在 React 组件挂载之前,会调用它的构造函数。

2.getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。

3.render(): render() 方法是 class 组件中唯一必须实现的方法。

4.componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。

render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

💃 更新

每当组件的 stateprops 发生变化时,组件就会更新。

当组件的 propsstate 发生变化时会触发更新。组件更新的生命周期调用顺序如下:

1.getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。

2.shouldComponentUpdate():当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。

3.render(): render() 方法是 class 组件中唯一必须实现的方法。

4.getSnapshotBeforeUpdate(): 在最近一次渲染输出(提交到 DOM 节点)之前调用。

5.componentDidUpdate(): 在更新后会被立即调用。

render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

💘 卸载

当组件从 DOM 中移除时会调用如下方法:

1.componentWillUnmount(): 在组件卸载及销毁之前直接调用。

😍 示例代码

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React 实例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>

<script type="text/babel">
class Button extends React.Component {
  constructor(props) {
      super(props);
      this.state = {data: 0};
      this.setNewNumber = this.setNewNumber.bind(this);
  }
  
  setNewNumber() {
    this.setState({data: this.state.data + 1})
  }
  render() {
      return (
         <div>
            <button onClick = {this.setNewNumber}>INCREMENT</button>
            <Content myNumber = {this.state.data}></Content>
         </div>
      );
    }
}


class Content extends React.Component {
  componentWillMount() {
      console.log('Component WILL MOUNT!')
  }
  componentDidMount() {
       console.log('Component DID MOUNT!')
  }
  componentWillReceiveProps(newProps) {
        console.log('Component WILL RECEIVE PROPS!')
  }
  shouldComponentUpdate(newProps, newState) {
        return true;
  }
  componentWillUpdate(nextProps, nextState) {
        console.log('Component WILL UPDATE!');
  }
  componentDidUpdate(prevProps, prevState) {
        console.log('Component DID UPDATE!')
  }
  componentWillUnmount() {
         console.log('Component WILL UNMOUNT!')
  }
 
    render() {
      return (
        <div>
          <h3>{this.props.myNumber}</h3>
        </div>
      );
    }
}
ReactDOM.render(
   <div>
      <Button />
   </div>,
  document.getElementById('example')
);
</script>

</body>
</html>

8.组件小实例

🍎 业务逻辑,在生命周期钩子函数里编写。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>组件</title>
</head>

<body>
  <div id="container">

  </div>
  <!-- react 核心js -->
  <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
  <!-- react-dom 渲染dom的js -->
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js" crossorigin></script>

  <script type="text/babel">
    class HelloBox extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          opacity: 1.0
        }
      }
      componentDidMount() {
        setInterval(() => {
          var opacity = this.state.opacity;
          opacity  -= .05;
          if(opacity < 0.1)opacity = 1.0
          this.setState({ opacity })
        }, 100);
      }
      render() {
        return (
          <div style={{ opacity: this.state.opacity }}>
            <h1>Malena Morgan {this.props.name}</h1>
          </div>
        )
      }
    }
    ReactDOM.render(<HelloBox name="naughty girl" />, document.getElementById('container'))
  </script>
</body>

</html>

🍌 页面显示

React简易上手指南

9.this.porps.children

this.porps 和组件属性是一一对应的。

this.porps.children 代表的是子节点。

通过 React.Children.map() 方法,可以遍历子节点。

class NotesList extends React.Component {
  render() {
    return (
      <ol>
        {
          React.Children.map(this.props.children, (child) => {
            return (<li>{child}</li>)
          })
        }
      </ol>
    )
  }
}
ReactDOM.render(
  <NotesList>
    <span>mila</span>
    <span>malena</span>
    <span>morgan</span>
    <span>naughty girl</span>
  </NotesList>,
  document.getElementById('container'))

10.组件的属性验证

🏀 props属性验证

为了确保组件引入的属性有意义,React引入propTypes机制。

React.PropTypes提供 validator 验证数据的有效性。

使用 PropTypes 进行类型检查,官网链接:

🚀使用 PropTypes 进行类型检查

正如官网所说:

自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替。

🚀prop-types 的 npm 地址

props属性验证,只在开发模式下起作用。生产模式下,不起作用,为了节省资源。

实际开发中,使用npm安装,这里做demo演示,直接引入

< script  src =" https://unpkg.com/prop-types@15.6/prop-types.js " > </ script >

🐯 示例代码

class MyTitle extends React.Component {
  render() {
    return (
      <h1>
        {this.props.title}
      </h1>
    )
  }
}

MyTitle.propTypes = {
  title: PropTypes.string.isRequired
}


var data = '123';

ReactDOM.render(<MyTitle title={data} />, document.getElementById('container'))

🍊 默认 Prop 值

通过配置特定的 defaultProps 属性来定义 props 的默认值:

 MyTitle.defaultProps = {
  title: 'ABCD'
}

11.ref获取真实DOM节点

🏃 如下所示,通过 this.refs.myTextInput 获取到真实DOM节点。

class MyComponent extends React.Component {
  handleClick = () => {
    this.refs.myTextInput.focus()
  }
  render(h) {
    return (
      <div>
        <input type="text" ref="myTextInput" />
        <input type="button" value="Focus the text input" onClick={this.handleClick} />
      </div>
    )
  }
}
ReactDOM.render(<MyComponent />, document.getElementById('container'))

12.表单bind复用

🔮 查看React官网关于表单的说明:

react.docschina.org/docs/forms.…

不同于Vue的双向数据绑定,React采用的是单向数据流,*

需要绑定onChange事件,通过setState改变state状态。

<input type="text" name="username" id="username" onChange={this.handleChange.bind(this, 'username')} value={this.state.username} />
handleChange = (name, event) => {
    var newState = {}
    newState[name] = name == 'checked' ? event.target.checked : event.target.value
    this.setState(newState)
    console.log(newState);
}

⌚ 表单示例demo

class MyForm extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      username: '',
      girl: 'mila',
      checked: true
    }
  }
  submitHandle = (e) => {
    e.preventDefault();
    var is = this.state.checked ? '是' : '不是'
    var style = this.state.girl == 'mila' ? 'naughty' : 'sexy';
    console.log(this.state.username + is + style);
  }
  handleChange = (name, event) => {
    var newState = {}
    newState[name] = name == 'checked' ? event.target.checked : event.target.value
    this.setState(newState)
    console.log(newState);
  }
  render(h) {
    return (
      <form onSubmit={this.submitHandle}>
        <label htmlFor="username">输入姓名</label>
        <input type="text" name="username" id="username" onChange={this.handleChange.bind(this, 'username')} value={this.state.username} />
        <br />
        <label htmlFor="checkbox">是或者否</label>
        <input type="checkbox" name="checked" id="checkbox" onChange={this.handleChange.bind(this, 'checked')} checked={this.state.checked} />
        <br />
        <label htmlFor="checkbox">选择girl</label>
        <select name="girl" onChange={this.handleChange.bind(this, 'girl')} value={this.state.girl}>
          <option value="mila">mila</option>
          <option value="malena">malena</option>
          <option value="morgan">morgan</option>
        </select>
        <br />
        <button type="submit">确定</button>
      </form>
    )
  }
}
ReactDOM.render(<MyForm />, document.getElementById('container'))

13.表单name复用

👑 给每一个标签设置 name,不通过 bind 绑定 onChange 事件,这种写法更加简化。

<input type="text" name="username" id="username" onChange={this.handleChange} value={this.state.username} />

修改 handleChange 方法

handleChange = (event) => {
    var newState = {}
    newState[event.target.name] = event.target.name == 'checked' ? event.target.checked : event.target.value
    this.setState(newState)
    console.log(newState);
  }

14.表单的可控组件

在 HTML 中,表单元素(如 input、 textarea 和 select)通常自己维护 state,并根据用户输入进行更新。

而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

🙋 表单demo中,使用的就是可控组件

  handleChange = (event) => {
    this.setState({ value: event.target.value })
    console.log(this.state.value);
  }

  render(h) {
    return (
      <input type="text" value={this.state.value} onChange={this.handleChange} />
    )
  }

15.表单的不可控组件

在大多数情况下,我们推荐使用 受控组件 来处理表单数据。在一个受控组件中,表单数据是由 React 组件来管理的。另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理。

要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。

写起来麻烦,不好复用。不推荐使用。

🐔 简单示例:

class MyForm extends React.Component {
  handleChange = (event) => {
    var inputValue = ReactDOM.findDOMNode(this.refs.input).value
    console.log(inputValue);
  }
  render(h) {
    return (
      <input type="text" onChange={this.handleChange} defaultValue="mila" ref="input"/>
    )
  }
}

🎀 官网示例:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.input = React.createRef();  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.current.value);    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

那么,这次就先写到这儿了。🏄

下次再整理更新。敬请期待。📌

参考资料

🚀菜鸟教程

🚀技术胖的React基础教程

最后的话

以上,如果对你有用的话,不妨点赞👍收藏💖关注一下,谢谢 🙏

您的支持,就是对我最大的帮助 😊

转载自:https://juejin.cn/post/7132364515059957796
评论
请登录