一、理解JavaScript纯函数

1.1 纯函数的概念

纯函数的维基百科定义:

  • 在程序设计中,若一个函数符合以下条件,那么这个函数被称为纯函数
  • 此函数在相同的输入值时,需产生相同的输出
  • 函数的输出和输入值以外的其他隐藏信息或状态无关,也和由I/O设备产生的外部输出无关
  • 该函数不能有语义上可观察的函数副作用,诸如“触发事件”,使输出设备输出,或更改输出值以外物件的内容

纯函数概念,总结如下:

  • 确定的输入,一定会产生确定的输出
  • 函数在执行过程中,不能产生副作用

案例(数组的两个方法):

  • slice:slice截取数组时不会对原数组进行任何操作,而是生成一个新的数组
  • splice:splice截取数组, 会返回一个新的数组,也会对原数组进行修改

1.2 副作用概念的理解

什么是副作用?

  • 副作用(side effect)表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响,比如修改了全局变量,修改参数或者改变外部的存储

纯函数在执行的过程中就是不能产生这样的副作用:

  • 副作用往往是产生bug的 “温床”

1.3 纯函数在函数式编程的重要性

为什么纯函数在函数式编程中非常重要呢?

  • 可以安心的编写和安心的使用
  • 在写的时候保证了函数的纯度,只是单纯实现自己的业务逻辑即可,不需要关心传入的内容是如何获得的或者依赖其他的外部变量是否已经发生了修改
  • 在用的时候,确定的输入内容不会被任意篡改,并且自己确定的输入,一定会有确定的输出
  • React中就要求我们无论是函数还是class声明一个组件,这个组件都必须像纯函数一样,保护它们的props不被修改
  • 在下面的redux中,reducer也被要求是一个纯函数

二、Redux的核心思想

2.1 为什么需要 Redux

JavaScript开发的应用程序变得越来越复杂:

  • JavaScript需要管理的状态越来越多,越来越复杂
  • 这些状态包括服务器返回的数据、缓存数据、用户操作产生的数据等等,也包括一些UI的状态,比如某些元素是否被选中,是否显示加载动效,当前分页

管理不断变化的state是非常困难的:

  • 状态之间相互会存在依赖,一个状态的变化会引起另一个状态的变化,View页面也有可能会引起状态的变化
  • 当应用程序复杂时,state在什么时候,因为什么原因而发生了变化,发生了怎么样的变化,会变得非常难以控制和追踪

React是在视图层帮助我们解决了DOM的渲染过程,但是State依然是留给我们自己来管理:

  • 无论是组件定义自己的state,还是组件之间的通信通过props进行传递;也包括通过Context进行数据之间的共享
  • React主要负责帮助我们管理视图,state如何维护最终还是我们自己来决定

  • Redux就是一个帮助我们管理State的容器:Redux是JavaScript的状态容器,提供了可预测的状态管理
  • Redux除了和React一起使用之外,它也可以和其他界面库一起来使用(比如Vue、小程序),并且它非常小(包括依赖在内,只有2kb)

2.2 Redux的核心概念

2.2.1 store

可以定义一些初始化的数据,通过 reducer 传入

2.2.2 action

  • store 中数据的变化,必须通过派发(dispatch)action来更新
  • action是一个普通的JavaScript对象,用来描述这次更新的type和content

2.2.3 reducer

将传入的state和action结合起来生成一个新的state

2.3 Redux的三大原则

2.3.1 单一数据源

  • 整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中
  • Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护
  • 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改

2.3.2 State是只读的

  • 唯一修改State的方法是触发action,不要试图在其他地方通过任何的方式来修改State
  • 这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改state
  • 这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题

2.3.3 使用纯函数来执行修改

  • 通过reducer将 旧state和 actions联系在一起,并且返回一个新的State
  • 随着应用程序的复杂度增加,可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分
  • 但是所有的reducer都应该是纯函数,不能产生任何的副作用

2.4 Redux 工作流程

建议看完Redux基本使用后再来看这幅图:

三、Redux基本使用

注意:以下 3 部分代码在 node 环境下

  • 需要安装redux:npm install redux

补充:node中对ES6模块化的支持

node v13.2.0开始,对ES6模块化提供了支持:

node v13.2.0之前,需要进行如下操作:

  • 在package.json中添加属性: "type": "module"
  • 在执行命令中添加如下选项:node --experimental-modules src/index.js

node v13.2.0之后,只需要进行如下操作:

  • 在package.json中添加属性: "type": "module"
  • 注意:导入文件时,需要跟上.js后缀名

3.1 创建Store的过程

定义reducer:必须是一个纯函数,不要直接修改state

createStore 传入 reducer

const { createStore } = require('redux')

// 初始化的数据
const initialState = {
  name: '李雷',
  counter: 100
}

// 定义reducer函数:纯函数
// 两个参数:
// 参数一:store中目前保存的state
// 参数二:本次需要更新的action(dispatch传入的action)
// 返回值:返回值会作为store之后存储的state
function reducer(state = initialState, action) {

  switch (action.type) {
    case 'change_name':
      return { ...state, name: action.name }

    case 'add_numer':
      return { ...state, counter: state.counter   action.num }

    default:
      return state
  }

}
// 创建store
const store = createStore(reducer)

module.exports = store

3.2 dispatch派发action

  • store 通过 dispatch 来派发 action
  • 通常会有 type 属性,也可以携带其他数据
const store = require('./store')

console.log(store.getState()) // { name: '李雷', counter: 100 }

// 修改store中的数据:必须action
const nameAction = { type: 'change_name', name: '韩梅梅' }
store.dispatch(nameAction)
console.log(store.getState()) // { name: '韩梅梅', counter: 100 }

const nameAction2 = { type: 'change_name', name: '夏洛' }
store.dispatch(nameAction2)
console.log(store.getState()) // { name: '夏洛', counter: 100 }

// 修改counter
const counterAction = { type: 'add_numer', num: 10 }
store.dispatch(counterAction)
console.log(store.getState()) // { name: '夏洛', counter: 110 }

3.3 subscribe定位state

  • store.subscribe()传入一个函数能够监听数据的变化
  • store.subscribe()会返回一个函数,执行该函数取消监听
const store = require('./store')

const unSubscribe = store.subscribe(() => {
  console.log('订阅数据的变化:', store.getState())
})

// 修改store中的数据:必须action
store.dispatch({ type: 'change_name', name: '韩梅梅' })
store.dispatch({ type: 'change_name', name: '夏洛' })

// 取消订阅
unSubscribe()

// 修改counter
store.dispatch({ type: 'add_numer', num: 10 })

3.4 代码优化

  • 优化方向:
    • action的创建放到一个函数中
    • 抽取到actionCreators.js文件中
    • 所有的字符串常量放到constants.js文件
    • reducer函数和初始化值, 放到reducer.js文件
    • index.js中创建store和导出store

示例:

actionCreators.js

const { ADD_NUMBER, CHANGE_NAME } = require("./constants")

const changeNameAction = (name) => ({
  type: CHANGE_NAME,
  name
})
const addNumberAction = (num) => ({
  type: ADD_NUMBER,
  num
})
module.exports = {
  changeNameAction,
  addNumberAction
}
const ADD_NUMBER = "add_number"
const CHANGE_NAME = "change_name"

module.exports = {
  ADD_NUMBER,
  CHANGE_NAME
}
const { CHANGE_NAME, ADD_NUMBER } = require('./constants')

// 初始化的数据
const initialState = {
  name: '李雷',
  counter: 100
}

function reducer(state = initialState, action) {
  switch (action.type) {
    case CHANGE_NAME:
      return { ...state, name: action.name }

    case ADD_NUMBER:
      return { ...state, counter: state.counter   action.num }

    default:
      return state
  }
}
module.exports = reducer
const { createStore } = require('redux')
const reducer = require('./reducer')

// 创建store
const store = createStore(reducer)

module.exports = store
const store = require('./store')

const { changeNameAction, addNumberAction } = require('./store/actionCreators')

store.dispatch(changeNameAction('独孤月'))
store.dispatch(addNumberAction(100))
console.log(store.getState()) // { name: '独孤月', counter: 200 }
  • constants.js
  • reducer.js
  • index.js
  • util.js 中使用

四、Redux 在 React中使用

4.1 先来一个案例

有两个组件,组件上展示同一个counter,并且两者能够对counter进行操作

  • 创建redux对应的store文件夹

actionCreators.js

import * as actionTypes from './constants'

export const addNumberAction = (num) => ({
  type: actionTypes.ADD_NUMBER,
  num
})

export const subNumberAction = (num) => ({
  type: actionTypes.SUB_NUMBER,
  num
})

constants.js

export const ADD_NUMBER = "add_number"
export const SUB_NUMBER = "sub_number"

reducer.js

import * as actionTypes from './constants'

const initialState = {
  counter: 100
}

function reducer(state = initialState, action) {
  switch (action.type) {
    case actionTypes.ADD_NUMBER:
      return { ...state, counter: state.counter   action.num }

    case actionTypes.SUB_NUMBER:
      return { ...state, counter: state.counter - action.num }

    default:
      return state
  }
}
export default reducer

index.js

import { createStore } from "redux"
import reducer from "./reducer"

const store = createStore(reducer)

export default store

组件中使用:

import React, { PureComponent } from 'react'

// 引入store
import store from '../store'
import { addNumberAction } from '../store/actionCreators'

export default class Home extends PureComponent {

  constructor() {
    super()

    this.state = {
      counter: store.getState().counter
    }
  }

  componentDidMount() {
    store.subscribe(() => {
      const state = store.getState()
      this.setState({ counter: state.counter })
    })
  }

  addNumber(num) {
    store.dispatch(addNumberAction(num))
  }

  render() {
    const { counter } = this.state
    return (
      <div>
        <h2>Home Counter: {counter}</h2>
        <div>
          <button onClick={e => this.addNumber(1)}> 1</button>
          <button onClick={e => this.addNumber(5)}> 5</button>
          <button onClick={e => this.addNumber(8)}> 8</button>
        </div>
      </div>
    )
  }
}
import React, { PureComponent } from 'react'

// 引入store
import store from '../store'
import { subNumberAction } from '../store/actionCreators'

export default class Profile extends PureComponent {
  constructor() {
    super()

    this.state = {
      counter: store.getState().counter
    }
  }
  componentDidMount() {
    store.subscribe(() => {
      const state = store.getState()
      this.setState({ counter: state.counter })
    })
  }
  subNumber(num) {
    store.dispatch(subNumberAction(num))
  }
  render() {
    const { counter } = this.state
    return (
      <div>
        <h2>Profile Counter: {counter}</h2>
        <div>
          <button onClick={e => this.subNumber(1)}>-1</button>
          <button onClick={e => this.subNumber(5)}>-5</button>
          <button onClick={e => this.subNumber(8)}>-8</button>
        </div>
      </div>
    )
  }
}
  • componentDidMount生命周期
  • store.subscribe(() => {}) => this.state => render
  • 修改数据:store.dispatch(addNumberAction(num))
  • Home.jsx
  • Profile.jsx

4.2 react-redux使用

安装:npm install react-redux

在使用时在入口文件中导入 Provider,传入 store

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

import { Provider } from 'react-redux';
import store from './store'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

在 About 组件中使用:

import React, { PureComponent } from 'react'

import { connect } from 'react-redux'
import { addNumberAction, subNumberAction } from '../store/actionCreators'

export class About extends PureComponent {

  clacNumber(num, isAdd) {
    if(isAdd) {
      this.props.addNumber(num)
    } else {
      this.props.subNumber(num)
    }
  }
  render() {
    const { counter } = this.props
    return (
      <div>
        <h2>About Counter: {counter}</h2>
        <button onClick={e => this.clacNumber(6, true)}> 6</button>
        <button onClick={e => this.clacNumber(9, true)}> 9</button>
        <button onClick={e => this.clacNumber(6, false)}>-6</button>
        <button onClick={e => this.clacNumber(9, false)}>-9</button>
      </div>
    )
  }
}
// connect() 返回值是一个高阶组件
// function mapStateToProps(state) {
//   return {
//     counter: state.counter
//   }
// }

const mapStateToProps = (state) => ({ counter: state.counter })

const mapDispatchToProps = (dispatch) => ({
  addNumber: num => dispatch(addNumberAction(num)),
  subNumber: num => dispatch(subNumberAction(num))
})

export default connect(mapStateToProps, mapDispatchToProps)(About)

connect():

  • 传入的第一个函数是映射当前组件所需要的数据(store中可能有很多数据,比如books、counter,而此处只需要counter)
  • 传入的第二个函数是映射 dispatch 到 props
  • 返回一个高阶组件

4.3 组件中的异步操作

4.3.1 类组件生命周期中请求数据

  • 在class组件的componentDidMount中发送请求

通过发起action将请求的数据保存到store中

action方法:

export const changeBannersAction = (banners) => ({
  type: actionTypes.CHANGE_BANNERS,
  banners
})

export const changeRecommendsAction = (recommends) => ({
  type: actionTypes.CHANGE_RECOMMENDS,
  recommends
})
import * as actionTypes from './constants'

const initialState = {
  counter: 100,

  banners: [],
  recommends: []
}

function reducer(state = initialState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_BANNERS:
      return { ...state, banners: action.banners }

    case actionTypes.CHANGE_RECOMMENDS:
      return { ...state, recommends: action.recommends }

    default:
      return state
  }
}

export default reducer
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import axios from 'axios'
import { changeBannersAction, changeRecommendsAction } from '../store/actionCreators'

export class Category extends PureComponent {

  componentDidMount() {
    // 发送请求
    axios.get('http://123.207.32.32:8000/home/multidata').then(res => {
      const banners = res.data.data.banner.list
      const recommends = res.data.data.recommend.list
      this.props.changeBanners(banners)
      this.props.changeRecommends(recommends)
    })
  }

  render() {
    return (
      <div>
        <h2>Category Page</h2>
      </div>
    )
  }
}

const mapDispatchToProps = (dispacth) => ({
  changeBanners: banners => dispacth(changeBannersAction(banners)),
  changeRecommends: recommends => dispacth(changeRecommendsAction(recommends))
})

export default connect(null, mapDispatchToProps)(Category)
  • reducer
  • category组件

4.3.2 使用中间件

上面的代码有一个缺陷:

  • 我们必须将网络请求的异步代码放到组件的生命周期中来完成
  • 事实上,网络请求到的数据也属于状态管理的一部分,更好的一种方式应该是将其也交给redux来管理

如何将异步请求交给 Redux?

  • 一个普通的action,返回的是一个对象 { type: CHANGE_COUNTER, num: 10 }
  • 对象中是无法直接拿到服务器请求到的异步数据的,但是如果返回一个函数呢?
  • 返回一个函数,然后在组件中发起 Action 的时候,执行这个函数是不是就能够拿到数据了呢!!!
  • !!! 普通的 action 不能返回函数,可以借助中间件来增强一下,让他支持返回一个函数,官网推荐的中间件:redux-thunk
  • 中间件的目的:是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码

redux-thunk 做了什么呢

  • dispatch(action函数)中的action可以是一个函数;
  • 该函数会被调用,并且会传给这个函数一个dispatch函数和getState函数;
    • dispatch函数用于之后再次派发action
    • getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于获取之前的一些状态

代码演示:

import { createStore, applyMiddleware } from "redux"
import thunk from "redux-thunk"
import reducer from "./reducer"

// 正常情况下 store.dispatch(object)
// 想要派发函数 store.dispatch(function)

// applyMiddleware 可以传入多个中间件,","隔开
const store = createStore(reducer, applyMiddleware(thunk))

export default store
import * as actionTypes from './constants'
import axios from 'axios'

export const changeBannersAction = (banners) => ({
  type: actionTypes.CHANGE_BANNERS,
  banners
})

export const changeRecommendsAction = (recommends) => ({
  type: actionTypes.CHANGE_RECOMMENDS,
  recommends
})

export const fetchHomeMultidataAction = () => {
  // 如果是一个普通的action,需要返回action对象
  // 问题: 对象中不能直接拿到从服务器请求的异步数据

  // redux 不允许返回一个函数,需要中间件
  return (dispatch, getState) => {
    // console.log(getState().counter) // 100
    // 进行异步操作: 网络请求
    axios.get('http://123.207.32.32:8000/home/multidata').then(res => {
      const banners = res.data.data.banner.list
      const recommends = res.data.data.recommend.list
      // dispatch({type: actionTypes.CHANGE_BANNERS, banners})
      // dispatch({type: actionTypes.CHANGE_RECOMMENDS, recommends})
      dispatch(changeBannersAction(banners))
      dispatch(changeRecommendsAction(recommends))
    })
  }

}
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { fetchHomeMultidataAction } from '../store/actionCreators'

export class Category extends PureComponent {

  componentDidMount() {
    this.props.fetchHomeMultidata()
  }

  render() {
    return (
      <div>
        <h2>Category Page</h2>
      </div>
    )
  }
}

const mapStateToProps = state => ({
  counter: state.counter
})

const mapDispatchToProps = (dispacth) => ({
  fetchHomeMultidata: () => dispacth(fetchHomeMultidataAction())
})

export default connect(mapStateToProps, mapDispatchToProps)(Category)
  • store(index.js) 中引入thunk
  • actionCreators.js
  • 组件中使用

4.4 redux-devtools

redux可以方便的对状态进行跟踪和调试

  • redux官网提供了redux-devtools的工具
  • 利用这个工具,可以知道每次状态是如何被修改的,修改前后的状态变化等等

安装该工具需要两步:

  • 在对应的浏览器中安装相关的插件(比如Chrome浏览器扩展商店中搜索Redux DevTools即可)
  • 在redux中继承devtools的中间件

默认该工具是未开启的,开发环境开启需要进行配置,生产环境千万千万不要打开哦!!!

import { createStore, applyMiddleware, compose } from "redux"
import thunk from "redux-thunk"
import reducer from "./reducer"

// redux-devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))

export default store
复制代码

4.5 模块拆分

正常情况下,我们的 store 中应该是有不同状态的数据,比如:购物车、用户信息等等, 如果将所有的状态都放到一个reducer中进行管理,随着项目的日趋庞大,必然会造成代码臃肿、难以维护。因此,我们可以对reducer进行拆分

以上面提到的案例为例,抽取一个 counter 的reducer和一个 home 的reducer,再将其合并起来

分不同的模块,每个模块都包含自己的核心:

>reducer:接收action对象,返回最新的state

  • constants:定义常量数据
  • actioncreators:定义创建action对象的函数
  • index:导出reducer

在 index.js 中导入每一个模块的内容,通过combineReducers合并之后放入createStore

import { createStore, applyMiddleware, compose, combineReducers } from "redux"
import thunk from "redux-thunk"

import counterReducer from './counter'
import homeReducer from './home'
import userReducer from './user'

// 将reducer合并到一起
const reducer = combineReducers({
  counter: counterReducer,
  home: homeReducer,
  user: userReducer
})

// redux-devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))

export default store

combineReducers 如何实现合并呢?

  • 事实上,它是将我们传入的reducers合并到一个对象中,最终返回一个combination的函数(相当于我们的reducer函数了)
  • 在执行combination函数的过程中,它会通过判断前后返回的数据是否相同来决定返回之前的state还是新的state
  • 新的state会触发订阅者发生对应的刷新,而旧的state可以有效的阻止订阅者发生刷新
// combineReducers 原理
function reducer(state = {}, action) {

  // 返回一个对象,store中的state
  return {
    counter: counterReducer(state.counter, action),
    home: homeReducer(state.home, action),
    user: userReducer(state.user, action)
  }
}

到此这篇关于一文详解React Redux使用方法的文章就介绍到这了,更多相关React Redux使用内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

一文详解React Redux使用方法的更多相关文章

  1. ios – React native链接到另一个应用程序

    如果是错误的,有人知道如何调用正确的吗?

  2. ios – React Native – 在异步操作后导航

    我正在使用ReactNative和Redux开发移动应用程序,我正面临着软件设计问题.我想调用RESTAPI进行登录,如果该操作成功,则导航到主视图.我正在使用redux和thunk所以我已经实现了异步操作,所以我的主要疑问是:我应该把逻辑导航到主视图?我可以直接从动作访问导航器对象并在那里执行导航吗?.我对组件中的逻辑没有信心.似乎不是一个好习惯.有没有其他方法可以做到这一点?

  3. 在ios中使用带有React Native(0.43.4)的cocoapods的正确方法是什么?

    我已经挖掘了很多帖子试图使用cocoapods为本地ios库设置一个反应原生项目,但我不可避免地在#import中找到了丢失文件的错误.我的AppDelegate.m文件中的语句.什么是使用反应原生的可可豆荚的正确方法?在这篇文章发表时,我目前的RN版本是0.43.4,而我正在使用Xcode8.2.1.这是我的过程,好奇我可能会出错:1)

  4. ios – 使用react-native-router-flux和redux,如何更新视图组件中的状态?

    为了完整起见,整个代码可以在github找到.解决方法您可能忘记将Launch组件连接到商店.你想要做的是类似于你在ExampleContainer中所做的,即然后正确的值将显示在您的日志中

  5. ios – React Native WebView滚动行为无法按预期工作

    如何确保滚动事件的行为与ReactNative应用程序中的浏览器相同?

  6. ios – React Native – BVLinearGradient – 找不到’React/RCTViewManager.h’文件

    谢谢.解决方法几天前我遇到了完全相同的问题.问题是在构建应用程序时React尚未链接.试试这个:转到Product=>Scheme=>管理方案…=>点击你的应用程序Scheme,然后点击Edit=>转到Build选项卡=>取消选中ParallelizeBuild然后点击标志添加目标=>搜索React,选择第一个名为React的目标,然后单击Add然后在目标列表中选择React并将其向上拖动到该列表中的第一个.然后转到Product=>再次清理并构建项目.这应该有所帮助.

  7. ios – React Native – NSNumber无法转换为NSString

    解决方法在你的fontWeight()函数中也许变成:

  8. ios – React native error – react-native-xcode.sh:line 45:react-native:command not found命令/ bin/sh失败,退出代码127

    尝试构建任何(新的或旧的)项目时出现此错误.我的节点是版本4.2.1,react-native是版本0.1.7.我看过其他有相同问题的人,所以我已经更新了本机的最新版本,但是我仍然无法通过xcode构建任何项目.解决方法要解决此问题,请使用以下步骤:>使用节点版本v4.2.1>cd进入[你的应用]/node_modules/react-native/packager>$sh./packager.s

  9. 反应原生 – 如何通过Xcode构建React Native iOS应用程序到设备?

    我试图将AwesomeProject应用程序构建到设备上.构建成功并启动屏幕显示,但后来我看到一个红色的“无法连接到开发服务器”屏幕.它表示“确保节点服务器正在运行–从Reactroot运行”npmstart“.看起来节点服务器已经运行,因为当我做npm启动时,我收到一个EADDRINUSE消息,表示该端口已经在使用.解决方法从设备访问开发服务器您可以使用开发服务器快速迭代设备.要做到这一点,你的

  10. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部