React 入门实例教程

目录

一、HTML 模板

 二、ReactDOM.render()

三、JSX 语法

四、组件

五、this.props.children 

六、PropTypes

七、获取真实的DOM节点

八、this.state

九、表单

十、组件的生命周期

constructor()

componentWillMount()

render()

componentDidMount()

组件生命周期 - 运行阶段(Updating)

componentWillReceiveProps()

shouldComponentUpdate()

componentWillUpdate()

组件生命周期 - 卸载阶段(Unmounting)

componentWillUnmount()

十一、Ajax

补充:

JSX的注意点

React组件

React创建组件的两种方式

JavaScript函数创建

class创建

给组件传递数据 - 父子组件传递数据

props和state

props

state

评论列表案例

style样式 

state和setState

组件绑定事件

React中的事件机制 - 推荐

事件绑定中的this

通过bind绑定

通过箭头函数绑定

受控组件

React 单向数据流

组件通讯

react-router

基本概念说明

使用步骤

注意点

路由参数

路由跳转

fetch

fetch 基本使用

跨域获取数据的三种常用方式

JSONP

代理

CORS - 服务器端配合

redux

核心



       本周由于刚入职的公司需要写react,自己也从网上借鉴了一些资料整合到自己的博客中,以便下次学习的时候方便回忆!

一、HTML 模板

使用 React 的网页源码,结构大致如下。


    
    
      
        
        
        
      
      
        

上面代码有两个地方需要注意。首先,最后一个

上面代码将一个 h1 标题,插入 example 节点。

输出结果如下:

React 入门实例教程_第1张图片

三、JSX 语法

上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写。

demo2:



  
    
    
    
    
  
  
    

上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。上面代码的运行结果如下:React 入门实例教程_第2张图片

JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员

demo3:



  
    
    
    
    
  
  
    

上面代码的arr变量是一个数组,结果 JSX 会把它的所有成员,添加到模板,运行结果如下

React 入门实例教程_第3张图片

四、组件

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类(查看 demo04)。



  
    
    
    
    
  
  
    

上面代码中,变量 HelloMessage 就是一个组件类。模板插入 时,会自动生成 HelloMessage 的一个实例(下文的"组件"都指组件类的实例)。所有组件类都必须有自己的 render 方法,用于输出组件。

注意,组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错。


    var HelloMessage = React.createClass({
      render: function() {
        return 

Hello {this.props.name}

some text

; } });

上面代码会报错,因为HelloMessage组件包含了两个顶层标签:h1p

组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。上面代码的运行结果如下。

React 入门实例教程_第4张图片

添加组件属性,有一个地方需要注意,就是 class 属性需要写成 classNamefor 属性需要写成 htmlFor ,这是因为 classfor 是 JavaScript 的保留字。

五、this.props.children 

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点(查看 demo05)



  
    
    
    
    
  
  
    

上面代码的 NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取,运行结果如下。

React 入门实例教程_第5张图片

这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。

React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。更多的 React.Children 的方法,请参考官方文档。

六、PropTypes

组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。

组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求(查看 demo06)



  
    
    
    
    
    
  
  
    

上面的Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值。

这样一来,title属性就通不过验证了。控制台会显示一行错误信息。

Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.

更多的PropTypes设置,可以查看官方文档。

此外,getDefaultProps 方法可以用来设置组件属性的默认值。


var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },

  render: function() {
     return 

{this.props.title}

; } }); ReactDOM.render( , document.body );

上面代码会输出"Hello World"。

七、获取真实的DOM节点

组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。

但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性(查看 demo07)



  
    
    
    
    
  
  
    

上面代码中,组件 MyComponent 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。

React 组件支持很多事件,除了 Click 事件以外,还有 KeyDownCopyScroll 等,完整的事件清单请查看官方文档。

八、this.state

组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI (查看 demo08 )。



  
    
    
    
    
  
  
    

上面代码是一个 LikeButton 组件,它的 getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。

由于 this.propsthis.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

九、表单

用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props 读取(查看 demo9 )



  
    
    
    
    
  
  
    

上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况,更多介绍请参考官方文档。

十、组件的生命周期

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

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。

  • componentWillMount()
  • componentDidMount()
  • componentWillUpdate(object nextProps, object nextState)
  • componentDidUpdate(object prevProps, object prevState)
  • componentWillUnmount()
constructor()
  • 作用:1 获取props 2 初始化state
  • 说明:通过 constructor() 的参数props获取
  • 设置state和props

 

class Greeting extends React.Component {
  constructor(props) {
    // 获取 props
    super(props)
    // 初始化 state
    this.state = {
      count: props.initCount
    }
  }
}

// 初始化 props
// 语法:通过静态属性 defaultProps 来初始化props
Greeting.defaultProps = {
  initCount: 0
};
componentWillMount()
  • 说明:组件被挂载到页面之前调用,其在render()之前被调用,因此在这方法里同步地设置状态将不会触发重渲染
  • 注意:无法获取页面中的DOM对象
  • 注意:可以调用 setState() 方法来改变状态值
  • 用途:发送ajax请求获取数据
componentWillMount() {
  console.warn(document.getElementById('btn')) // null
  this.setState({
    count: this.state.count + 1
  })
}
render()
  • 作用:渲染组件到页面中,无法获取页面中的DOM对象
  • 注意:不要在render方法中调用 setState() 方法,否则会递归渲染

    • 原因说明:状态改变会重新调用render()render()又重新改变状态
render() {
  console.warn(document.getElementById('btn')) // null

  return (
    
{ this.state.count === 4 ? null : }
) }
componentDidMount()
  • 1 组件已经挂载到页面中
  • 2 可以进行DOM操作,比如:获取到组件内部的DOM对象
  • 3 可以发送请求获取数据
  • 4 可以通过 setState() 修改状态的值
  • 注意:在这里修改状态会重新渲染
componentDidMount() {
  // 此时,就可以获取到组件内部的DOM对象
  console.warn('componentDidMount', document.getElementById('btn'))
}

组件生命周期 - 运行阶段(Updating)

  • 特点:该阶段的函数执行多次
  • 说明:每当组件的props或者state改变的时候,都会触发运行阶段的函数
componentWillReceiveProps()
  • 说明:组件接受到新的props前触发这个方法
  • 参数:当前组件props
  • 可以通过 this.props 获取到上一次的值
  • 使用:若你需要响应属性的改变,可以通过对比this.propsnextProps并在该方法中使用this.setState()处理状态改变
  • 注意:修改state不会触发该方法
componentWillReceiveProps(nextProps) {
  console.warn('componentWillReceiveProps', nextProps)
}
shouldComponentUpdate()
  • 作用:根据这个方法的返回值决定是否重新渲染组件,返回true重新渲染,否则不渲染
  • 优势:通过某个条件渲染组件,降低组件渲染频率,提升组件性能
  • 说明:如果返回值为false,那么,后续render()方法不会被调用
  • 注意:这个方法必须返回布尔值!!!
  • 场景:根据随机数决定是否渲染组件
// - 参数:
//   - 第一个参数:最新属性对象
//   - 第二个参数:最新状态对象
shouldComponentUpdate(nextProps, nextState) {
  console.warn('shouldComponentUpdate', nextProps, nextState)

  return nextState.count % 2 === 0
}
componentWillUpdate()
  • 作用:组件将要更新
  • 参数:最新的属性和状态对象
  • 注意:不能修改状态 否则会循环渲染
componentWillUpdate(nextProps, nextState) {
  console.warn('componentWillUpdate', nextProps, nextState)
}

组件生命周期 - 卸载阶段(Unmounting)

  • 组件销毁阶段:组件卸载期间,函数比较单一,只有一个函数,这个函数也有一个显著的特点:组件一辈子只能执行依次!
  • 使用说明:只要组件不再被渲染到页面中,那么这个方法就会被调用( 渲染到页面中 -> 不再渲染到页面中 )
componentWillUnmount()
  • 作用:在卸载组件的时候,执行清理工作,比如

    • 1 清除定时器
    • 2 清除componentDidMount创建的DOM对象

此外,React 还提供两种特殊状态的处理函数。

  • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
  • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

这些方法的详细说明,可以参考官方文档。下面是一个例子(查看 demo10 )。



  
    
    
    
    
  
  
    

上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。

另外,组件的style属性的设置方式也值得注意,不能写成


style="opacity:{this.state.opacity};"

而要写成


style={{opacity: this.state.opacity}}

这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。

十一、Ajax

组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI (查看 demo11 )。



  
    
    
    
    
    
  
  
    

上面代码使用 jQuery 完成 Ajax 请求,这是为了便于说明。React 本身没有任何依赖,完全可以不用jQuery,而使用其他库。

我们甚至可以把一个Promise对象传入组件,请看Demo12。



  
    
    
    
    
    
  
  
    

补充:

JSX的注意点

  • 注意 1: 如果在 JSX 中给元素添加类, 需要使用 className 代替 class

    • 类似:label 的 for属性,使用htmlFor代替
  • 注意 2:在 JSX 中可以直接使用 JS代码,直接在 JSX 中通过 {} 中间写 JS代码即可
  • 注意 3:在 JSX 中只能使用表达式,但是不能出现 语句!!!
  • 注意 4:在 JSX 中注释语法:{/* 中间是注释的内容 */}

React组件

React 组件可以让你把UI分割为独立、可复用的片段,并将每一片段视为相互独立的部分。
  • 组件是由一个个的HTML元素组成的
  • 概念上来讲, 组件就像JS中的函数。它们接受用户输入(props),并且返回一个React对象,用来描述展示在页面中的内容

React创建组件的两种方式

  • 1 通过 JS函数 创建(无状态组件)
  • 2 通过 class 创建(有状态组件)
函数式组件 和 class 组件的使用场景说明:
1 如果一个组件仅仅是为了展示数据,那么此时就可以使用 函数组件
2 如果一个组件中有一定业务逻辑,需要操作数据,那么就需要使用 class 创建组件,因为,此时需要使用 state
JavaScript函数创建
  • 注意:1 函数名称必须为大写字母开头,React通过这个特点来判断是不是一个组件
  • 注意:2 函数必须有返回值,返回值可以是:JSX对象或null
  • 注意:3 返回的JSX,必须有一个根元素
  • 注意:4 组件的返回值使用()包裹,避免换行问题
function Welcome(props) {
  return (
    // 此处注释的写法 
    
{/* 此处 注释的写法 必须要{}包裹 */}

Shopping List for {props.name}

  • Instagram
  • WhatsApp
) } ReactDOM.render( , document.getElementById('app') )
class创建
在es6中class仅仅是一个语法糖,不是真正的类,本质上还是构造函数+原型 实现继承
// ES6中class关键字的简单使用

// - **ES6中的所有的代码都是运行在严格模式中的**
// - 1 它是用来定义类的,是ES6中实现面向对象编程的新方式
// - 2 使用`static`关键字定义静态属性
// - 3 使用`constructor`构造函数,创建实例属性
// - [参考](http://es6.ruanyifeng.com/#docs/class)

// 语法:
class Person {
  // 实例的构造函数 constructor
  constructor(age){
    // 实例属性
    this.age = age
  }
  // 在class中定义方法 此处为实例方法 通过实例打点调用
  sayHello () {
    console.log('大家好,我今年' + this.age + '了');
  }

  // 静态方法 通过构造函数打点调用 Person.doudou()
  static doudou () {
    console.log('我是小明,我新get了一个技能,会暖床');
  }
}
// 添加静态属性
Person.staticName = '静态属性'
// 实例化对象
const p = new Person(19)
 
 
// 实现继承的方式
 
class American extends Person {
  constructor() {
    // 必须调用super(), super表示父类的构造函数
    super()
    this.skin = 'white'
    this.eyeColor = 'white'
  }
}

// 创建react对象
// 注意:基于 `ES6` 中的class,需要配合 `babel` 将代码转化为浏览器识别的ES5语法
// 安装:`npm i -D babel-preset-env`
 
//  react对象继承字React.Component
class ShoppingList extends React.Component {
  constructor(props) { 
    super(props)
  }
  // class创建的组件中 必须有rander方法 且显示return一个react对象或者null
  render() {
    return (
      

Shopping List for {this.props.name}

  • Instagram
  • WhatsApp
) } }

给组件传递数据 - 父子组件传递数据

  • 组件中有一个 只读的对象 叫做 props,无法给props添加属性
  • 获取方式:函数参数 props
  • 作用:将传递给组件的属性转化为 props 对象中的属性
function Welcome(props){
  // props ---> { username: 'zs', age: 20 }
  return (
    
Welcome React

姓名:{props.username}----年龄是:{props.age}

) } // 给 Hello组件 传递 props:username 和 age(如果你想要传递numb类型是数据 就需要向下面这样) ReactDOM.reander(, ......)

 封装组件到独立的文件中

// 创建Hello2.js组件文件
// 1. 引入React模块
// 由于 JSX 编译后会调用 React.createElement 方法,所以在你的 JSX 代码中必须首先拿到React。
import React from 'react'

// 2. 使用function构造函数创建组件
function Hello2(props){
  return (
    
这是Hello2组件

这是大大的H1标签,我大,我骄傲!!!

这是小小的h6标签,我小,我傲娇!!!
) } // 3. 导出组件 export default Hello2 // app.js中 使用组件: import Hello2 from './components/Hello2'

props和state

props

  • 作用:给组件传递数据,一般用在父子组件之间
  • 说明:React把传递给组件的属性转化为一个对象并交给 props
  • 特点:props是只读的,无法给props添加或修改属性
  • props.children:获取组件的内容,比如:

    • 组件内容 中的 组件内容
// props 是一个包含数据的对象参数,不要试图修改 props 参数
// 返回值:react元素
function Welcome(props) {
  // 返回的 react元素中必须只有一个根元素
  return 
hello, {props.name}
} class Welcome extends React.Component { constructor(props) { super(props) } render() { return

Hello, {this.props.name}

} }

state

状态即数据
  • 作用:用来给组件提供组件内部使用的数据
  • 注意:只有通过class创建的组件才具有状态
  • 注意:状态是私有的,完全由组件来控制
  • 注意:不要在 state 中添加 render() 方法中不需要的数据,会影响渲染性能!

    • 可以将组件内部使用但是不渲染在视图中的内容,直接添加给 this
  • 注意:不要在 render() 方法中调用 setState() 方法来修改state的值

    • 但是可以通过 this.state.name = 'rose' 方式设置state(不推荐!!!!)
// 例:
class Hello extends React.Component {
  constructor() {
    // es6继承必须用super调用父类的constructor
    super()

    this.state = {
      gender: 'male'
    }
  }

  render() {
    return (
      
性别:{ this.state.gender }
) } }

评论列表案例

  • 巩固有状态组件和无状态组件的使用
  • 两个组件:
[
  { user: '张三', content: '哈哈,沙发' },
  { user: '张三2', content: '哈哈,板凳' },
  { user: '张三3', content: '哈哈,凉席' },
  { user: '张三4', content: '哈哈,砖头' },
  { user: '张三5', content: '哈哈,楼下山炮' }
]

// 属性扩展

style样式 

// 1. 直接写行内样式:
  • // 2. 抽离为对象形式 var styleH3 = {color:'blue'} var styleObj = { liStyle:{border:'1px solid red', fontSize:'12px'}, h3Style:{color:'green'} }
  • 评论内容:{props.content}

  • // 3. 使用样式表定义样式: import '../css/comment.css'

    评论人:{props.user}

    state和setState

    • 注意:使用 setState() 方法修改状态,状态改变后,React会重新渲染组件
    • 注意:不要直接修改state属性的值,这样不会重新渲染组件!!!
    • 使用:1 初始化state 2 setState修改state
    // 修改state(不推荐使用)
    // https://facebook.github.io/react/docs/state-and-lifecycle.html#do-not-modify-state-directly
    this.state.test = '这样方式,不会重新渲染组件';
    constructor(props) {
      super(props)
    
      // 正确姿势!!!
      // -------------- 初始化 state --------------
      this.state = {
        count: props.initCount
      }
    }
    
    componentWillMount() {
      // -------------- 修改 state 的值 --------------
      // 方式一:
      this.setState({
        count: this.state.count + 1
      })
    
      this.setState({
        count: this.state.count + 1
      }, function(){
        // 由于 setState() 是异步操作,所以,如果想立即获取修改后的state
        // 需要在回调函数中获取
        // https://doc.react-china.org/docs/react-component.html#setstate
      });
    
      // 方式二:
      this.setState(function(prevState, props) {
        return {
          counter: prevState.counter + props.increment
        }
      })
    
      // 或者 - 注意: => 后面需要带有小括号,因为返回的是一个对象
      this.setState((prevState, props) => ({
        counter: prevState.counter + props.increment
      }))
    }

    组件绑定事件

    • 1 通过React事件机制 onClick 绑定
    • 2 JS原生方式绑定(通过 ref 获取元素)

      • 注意:ref 是React提供的一个特殊属性
      • ref的使用说明:react ref

    React中的事件机制 - 推荐

    • 注意:事件名称采用驼峰命名法
    • 例如:onClick 用来绑定单击事件

    事件绑定中的this

    • 1 通过 bind 绑定
    • 2 通过 箭头函数 绑定

    通过bind绑定

    • 原理:bind能够调用函数,改变函数内部this的指向,并返回一个新函数
    • 说明:bind第一个参数为返回函数中this的指向,后面的参数为传给返回函数的参数
    // 自定义方法:
    handleBtnClick(arg1, arg2) {
      this.setState({
        msg: '点击事件修改state的值' + arg1 + arg2
      })
    }
    
    render() {
      return (
        

    {this.state.msg}

    ) }

     在构造函数中使用bind:

    constructor() {
      super()
    
      this.handleBtnClick = this.handleBtnClick.bind(this)
    }
    
    // render() 方法中:
    

    通过箭头函数绑定

    • 原理:箭头函数中的this由所处的环境决定,自身不绑定this
     { this.handleBtnClick('参数1', '参数2') }
    } />
    
    handleBtnClick(arg1, arg2) {
      this.setState({
        msg: '在构造函数中绑定this并传参' + arg1 + arg2
      });
    }

    受控组件

    • 表单和受控组件
    • 非受控组件
    在HTML当中,像 input, textareaselect这类表单元素会维持自身状态,并根据用户输入进行更新。
    在React中,可变的状态通常保存在组件的 state中,并且只能用 setState() 方法进行更新.
    React根据初始状态渲染表单组件,接受用户后续输入,改变表单组件内部的状态。
    因此,将那些值由React控制的表单元素称为:受控组件。
    • 受控组件的特点:

      • 1 表单元素
      • 2 由React通过JSX渲染出来
      • 3 由React控制值的改变,也就是说想要改变元素的值,只能通过React提供的方法来修改
    • 注意:只能通过setState来设置受控组件的值
    // 模拟实现文本框数据的双向绑定
    
    
    // 当文本框内容改变的时候,触发这个事件,重新给state赋值
    handleTextChange = event => {
      console.log(event.target.value)
    
      this.setState({
        msg: event.target.value
      })
    }

    React 单向数据流

    • React 中采用单项数据流
    • 数据流动方向:自上而下,也就是只能由父组件传递到子组件
    • 数据都是由父组件提供的,子组件想要使用数据,都是从父组件中获取的
    • 如果多个组件都要使用某个数据,最好将这部分共享的状态提升至他们最近的父组件当中进行管理
    • 单向数据流
    • 状态提升

    react中的单向数据流动:
    1 数据应该是从上往下流动的,也就是由父组件将数据传递给子组件
    2 数据应该是由父组件提供,子组件要使用数据的时候,直接从子组件中获取

    在我们的评论列表案例中:数据是由CommentList组件(父组件)提供的
    子组件 CommentItem 负责渲染评论列表,数据是由 父组件提供的
    子组件 CommentForm 负责获取用户输入的评论内容,最终也是把用户名和评论内容传递给了父组件,由父组件负责处理这些数据( 把数据交给 CommentItem 由这个组件负责渲染 )

     

    组件通讯

    • 父 -> 子:props
    • 子 -> 父:父组件通过props传递回调函数给子组件,子组件调用函数将数据作为参数传递给父组件
    • 兄弟组件:因为React是单向数据流,因此需要借助父组件进行传递,通过父组件回调函数改变兄弟组件的props
    • React中的状态管理: flux(提出状态管理的思想) -> Redux -> mobx
    • Vue中的状态管理: Vuex
    • 简单来说,就是统一管理了项目中所有的数据,让数据变的可控
    • 组件通讯

    react-router

    • react router 官网
    • react router github
    • 安装:npm i -S react-router-dom

    基本概念说明

    • Router组件本身只是一个容器,真正的路由要通过Route组件定义

    使用步骤

    • 1 导入路由组件
    • 2 使用 作为根容器,包裹整个应用(JSX)

      • 在整个应用程序中,只需要使用一次
    • 3 使用 作为链接地址,并指定to属性
    • 4 使用 展示路由内容
    // 1 导入组件
    import {
      HashRouter as Router,
      Link, Route
    } from 'react-router-dom'
    
    // 2 使用 
    
    
        // 3 设置 Link
        首页
        电影
        关于
    
        // 4 设置 Route
        // exact 表示:绝对匹配(完全匹配,只匹配:/)
        
        
        
    
    

    注意点

    • :作为整个组件的根元素,是路由容器,只能有一个唯一的子元素
    • :类似于vue中的标签,to 属性指定路由地址
    • :类似于vue中的,指定路由内容(组件)展示位置

    路由参数

    • 配置:通过Route中的path属性来配置路由参数
    • 获取:this.props.match.params 获取
    // 配置路由参数
    
    
    // 获取路由参数
    const type = this.props.match.params.movieType

    路由跳转

    • react router - history
    • history.push() 方法用于在JS中实现页面跳转
    • history.go(-1) 用来实现页面的前进(1)和后退(-1)
    this.props.history.push('/movie/movieDetail/' + movieId)

    fetch

    • 作用:Fetch 是一个现代的概念, 等同于 XMLHttpRequest。它提供了许多与XMLHttpRequest相同的功能,但被设计成更具可扩展性和高效性。
    • fetch() 方法返回一个Promise对象

    fetch 基本使用

    • fetch Response
    • fetch 介绍
    • Javascript 中的神器——Promise
    /*
      通过fetch请求回来的数据,是一个Promise对象.
      调用then()方法,通过参数response,获取到响应对象
      调用 response.json() 方法,解析服务器响应数据
      再次调用then()方法,通过参数data,就获取到数据了
    */
    fetch('/api/movie/' + this.state.movieType)
      // response.json() 读取response对象,并返回一个被解析为JSON格式的promise对象
      .then((response) => response.json())
      // 通过 data 获取到数据
      .then((data) => {
        console.log(data);
        this.setState({
          movieList: data.subjects,
          loaing: false
        })
      })

    跨域获取数据的三种常用方式

    • 1 JSONP
    • 2 代理
    • 3 CORS

    JSONP

    • 安装:npm i -S fetch-jsonp
    • 利用JSONP实现跨域获取数据,只能获取GET请求
    • fetch-jsonp
    • fetch-jsonp
    • 限制:1 只能发送GET请求 2 需要服务端支持JSONP请求
    /* movielist.js */
    fetchJsonp('https://api.douban.com/v2/movie/in_theaters')
      .then(rep => rep.json())
      .then(data => { console.log(data) })

    代理

    • webpack-dev-server 代理配置如下:
    • 问题:webpack-dev-server 是开发期间使用的工具,项目上线了就不再使用 webpack-dev-server
    • 解决:项目上线后的代码,也是会部署到一个服务器中,这个服务器配置了代理功能即可(要求两个服务器中配置的代理规则相同)
    // webpack-dev-server的配置
    devServer: {
      // https://webpack.js.org/configuration/dev-server/#devserver-proxy
      // https://github.com/chimurai/http-proxy-middleware#http-proxy-options
      // http://www.jianshu.com/p/3bdff821f859
      proxy: {
        // 使用:/api/movie/in_theaters
        // 访问 ‘/api/movie/in_theaters’ ==> 'https://api.douban.com/v2/movie/in_theaters'
        '/api': {
          // 代理的目标服务器地址
          target: 'https://api.douban.com/v2',
          // https请求需要该设置
          secure: false,
          // 必须设置该项
          changeOrigin: true,
          // '/api/movie/in_theaters' 路径重写为:'/movie/in_theaters'
          pathRewrite: {"^/api" : ""}
        }
      }
    }
    
    /* movielist.js */
    fetch('/api/movie/in_theaters')
      .then(function(data) {
        // 将服务器返回的数据转化为 json 格式
        return data.json()
      })
      .then(function(rep) {
        // 获取上面格式化后的数据
        console.log(rep);
      })

    CORS - 服务器端配合

    // 通过Express的中间件来处理所有请求
    app.use('*', function (req, res, next) {
      // 设置请求头为允许跨域
      res.header('Access-Control-Allow-Origin', '*');
    
      // 设置服务器支持的所有头信息字段
      res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization,Accept,X-Requested-With');
      // 设置服务器支持的所有跨域请求的方法
      res.header('Access-Control-Allow-Methods', 'POST,GET');
      // next()方法表示进入下一个路由
      next();
    });

    redux

    • 状态管理工具,用来管理应用中的数据

    核心

    • Action:行为的抽象,视图中的每个用户交互都是一个action

      • 比如:点击按钮
    • Reducer:行为响应的抽象,也就是:根据action行为,执行相应的逻辑操作,更新state

      • 比如:点击按钮后,添加任务,那么,添加任务这个逻辑放到 Reducer 中
      • 1 创建State
    • Store:

      • 1 Redux应用只能有一个store
      • 2 getState():获取state
      • 3 dispatch(action):更新state
    /* action */
    
    // 在 redux 中,action 就是一个对象
    // action 必须提供一个:type属性,表示当前动作的标识
    // 其他的参数:表示这个动作需要用到的一些数据
    { type: 'ADD_TODO', name: '要添加的任务名称' }
    
    // 这个动作表示要切换任务状态
    { type: 'TOGGLE_TODO', id: 1 }
    /* reducer */
    
    // 第一个参数:表示状态(数据),我们需要给初始状态设置默认值
    // 第二个参数:表示 action 行为
    function todo(state = [], action) {
      switch(action.type) {
        case 'ADD_TODO':
          state.push({ id: Math.random(), name: action.name, completed: false })
          return state
        case 'TOGGLE_TODO':
          for(var i = 0; i < state.length; i++) {
            if (state[i].id === action.id) {
              state[i].completed = !state[i].completed
              break
            }
          }
          return state
        default:
          return state
      }
    }
    
    // 要执行 ADD_TODO 这个动作:
    dispatch( { type: 'ADD_TODO', name: '要添加的任务名称' } )
    
    // 内部会调用 reducer
    todo(undefined, { type: 'ADD_TODO', name: '要添加的任务名称' })

    你可能感兴趣的:(React,javascript,前端,react.js)