redux介绍

学习文档英文文档中文文档Github

redux是什么

redux是一个独立专门用于做状态管理的JS库(不是react插件库),它可以用在react, angular, vue等项目中, 但基本与react配合使用

作用: 集中式管理react应用中多个组件共享的状态

redux工作流程

将会把这个过程比拟成图书馆的一个流程来帮助理解

Action Creator(具体借书的表达) :想借书的人向图书馆管理员说明要借的书的那句话

Store(图书馆管理员) :负责整个图书馆的管理。是Redux的核心

Reducers(图书馆管理员的小本本) :管理员需要借助Reducer(图书馆管理员的小本本)来记录。

React Component(借书的人 ) :需要借书的人

借书的人(ReactComponent)说了一句话(Action Creator)向图书馆管理员(Store)借一本书,可是图书馆管理员年纪大了啊记不住啊,便掏出了自己的小本本(Reducers)。看了看知道了那本书有没有,在哪,怎么样。这样一来管理员就拿到了这本书,再把这本书交给了借书人

翻译过来就是:组件想要获取State, 用ActionCreator创建了一个请求交给Store,Store借助Reducer确认了该State的状态,Reducer返回给Store一个结果,Store再把这个State转给组件。

什么情况下需要使用redux

总体原则: 能不用就不用, 如果不用比较吃力才考虑使用,某个组件的状态,需要共享,某个状态需要在任何地方都可以拿到

一个组件需要改变全局状态,一个组件需要改变另一个组件的状态

不用redux的方式实现更改状态

首先我们创建一个项目,创建应用目录和文件如下

将创建的main.js组件在App.js入口组件中引入

import React from 'react';
import './App.css'; import Main from './views/main/main'
function App() {
return (
<div className="App">
<Main/>
</div>
);
} export default App;

并且在main.js这个组件中实现如下的组件

import React from 'react';
import './main.css'; class Main extends React.Component{
state = {
count: 0
}
increment = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 因为的到的是字符串所以乘以1隐式转换成number
// 2. 读取原本state中的count状态,并且计算新的count
const count = this.state.count + number
// 3. 更新state的count状态
this.setState({
count // 完整的写法式count: count,因为名字相同所以直接写一个count即可
})
}
decrement = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态,并且计算新的count
const count = this.state.count - number
// 3. 更新state的count状态
this.setState({
count
})
}
incrementIfOdd = ()=> {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态
const count = this.state.count
// 3. 判断当前状态如果式奇数才更新
if (count%2 === 1) {
// 4. 更新state的count状态
this.setState({
count: count + number
})
} }
incrementAsync =() => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态
const count = this.state.count // 启动延时定时器
setTimeout(() => {
// 3. 异步更新state的count状态
this.setState({
count: count + number
})
},1000)
}
render() {
const {count} = this.state
return (
<div className="App">
<p>click {count} times</p>
<div>
<select ref={select => this.select = select}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>increment if odd</button>
<button onClick={this.incrementAsync}>increment async</button>
</div>
</div>
);
}
} export default Main;

以上我们使用正常的方式实现了上图中的效果,接下来改造成redux的方式去实现,先来看看redux的核心API

redux的核心API

store

就是保存数据的地方,你可以把它看成一个数据,整个应用智能有一个store,Redux提供createStore这个函数,用来生成Store

state

就是store里面存储的数据,store里面可以拥有多个state,Redux规定一个state对应一个View,只要state相同,view就是一样的,反过来也是一样的,可以通过store.getState( )获取

Action

state的改变会导致View的变化,但是在redux中不能直接操作state也就是说不能使用this.setState来操作,用户只能接触到View。在Redux中提供了一个对象来告诉Store需要改变state。

Action是一个对象其中type属性是必须的,表示Action的名称,其他的可以根据需求自由设置。

store.dispatch( )

store.dispatch( )是view触发Action的唯一办法,store.dispatch接收一个Action作为参数,将它发送给store通知store来改变state。

Reducer

Store收到Action以后,必须给出一个新的state,这样view才会发生变化。这种state的计算过程就叫做Reducer。Reducer是一个纯函数,他接收Action和当前state作为参数,返回一个新的state

redux的基本使用

首先下载安装redux的依赖包

npm install --save redux

项目根目录创建一个专门管理redux的文件夹,并且创建action-types.js文件,用于管理action对象的type常量名称模块

// action对象的type常量名称模块

export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

然后再redux目录中创建reducer函数的模块:reducers.js

/*包含n个reducer函数的模块*/

// 根据老的state和指定action, 处理返回一个新的state

import {INCREMENT, DECREMENT} from './action-types'

export function counter(state = 0, action) {
switch (action.type) {
case INCREMENT:
return state + action.data
case DECREMENT:
return state - action.data
default:
return state
}
}

然后在项目入口文件index.js中引入这个reducer函数counter,并且将这个counter放到createStore方法中返回一个store对象

store对象的作用是redux库最核心的管理对象,它内部维护着state和reducer,核心方法有getState(),dispatch(action),subscribe(listener)

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {createStore} from 'redux';
import {counter} from './redux/reducers'; // 创建一个store对象
// createStore()的作用是创建包含指定reducer的store对象
const store = createStore(counter); // 内部会第一次调用reduer函数得到初始state console.log(store);//store对象 ReactDOM.render(<App store={store} />, document.getElementById('root')); // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

然后在应用组件中使用(需要将store通过props传递到需要使用的组件中)

import React from 'react';
import './App.css';
import PropTypes from 'prop-types' import Main from './views/main/main'
class App extends React.Component {
static propTypes = {
store: PropTypes.object.isRequired,
} render() {
return (
<div className="App">
<Main store={this.props.store}/>
</div>
);
}
} export default App;
import React from 'react';
import './main.css';
import PropTypes from "prop-types";
import {INCREMENT, DECREMENT} from '../../redux/action-types' class Main extends React.Component{
static propTypes = {
store: PropTypes.object.isRequired,
}
increment = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 因为的到的是字符串所以乘以1隐式转换成number // 2. 调用store的方法更新状态
this.props.store.dispatch({
type: INCREMENT,
data: number
})
}
decrement = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 2. 调用store的方法更新状态
this.props.store.dispatch({
type: DECREMENT,
data: number
})
}
incrementIfOdd = ()=> {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态
const count = this.props.store.getState()
// 3. 判断当前状态如果式奇数才更新
if (count%2 === 1) {
// 4. 调用store的方法更新状态
this.props.store.dispatch({
type: INCREMENT,
data: number
})
}
}
incrementAsync =() => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1// 启动延时定时器
setTimeout(() => {
// 2. 调用store的方法更新状态
this.props.store.dispatch({
type: INCREMENT,
data: number
})
},1000)
}
render() {
const count = this.props.store.getState()
return (
<div className="App">
<p>click {count} times</p>
<div>
<select ref={select => this.select = select}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>increment if odd</button>
<button onClick={this.incrementAsync}>increment async</button>
</div>
</div>
);
}
} export default Main;

subscribe(listener),状态更新了之后需要调用这个方法来刷新

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {createStore} from 'redux';
import {counter} from './redux/reducers'; // 创建一个store对象
// createStore()的作用是创建包含指定reducer的store对象
const store = createStore(counter); // 内部会第一次调用reduer函数得到初始state console.log(store);//store对象 function render () {
ReactDOM.render(<App store={store} />, document.getElementById('root'));
}
render() // 初始化渲染 store.subscribe(render) // 订阅监听(store中的状态变化了就会自动调用进行重绘) // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

可以把要执行的行为对象action单独抽离出来一个模块,使用工厂函数的方式(官方推荐的写法),在redux文件夹中创建一个actions.js

/*action creator模块*/
import {INCREMENT, DECREMENT} from './action-types' export const increment = number => ({type: INCREMENT, data: number})
export const decrement = number => ({type: DECREMENT, data: number})
import React from 'react';
import './main.css';
import PropTypes from "prop-types";
import * as actions from '../../redux/actions' class Main extends React.Component{
static propTypes = {
store: PropTypes.object.isRequired,
}
increment = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 因为的到的是字符串所以乘以1隐式转换成number // 2. 调用store的方法更新状态
this.props.store.dispatch(actions.increment(number))
}
decrement = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 2. 调用store的方法更新状态
this.props.store.dispatch(actions.decrement(number))
}
incrementIfOdd = ()=> {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态
const count = this.props.store.getState()
// 3. 判断当前状态如果式奇数才更新
if (count%2 === 1) {
// 4. 调用store的方法更新状态
this.props.store.dispatch(actions.increment(number))
}
}
incrementAsync =() => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 启动延时定时器
setTimeout(() => {
// 2. 调用store的方法更新状态
this.props.store.dispatch(actions.increment(number))
},1000)
}
render() {
const count = this.props.store.getState()
return (
<div className="App">
<p>click {count} times</p>
<div>
<select ref={select => this.select = select}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>increment if odd</button>
<button onClick={this.incrementAsync}>increment async</button>
</div>
</div>
);
}
} export default Main;

还有一个就是将store搬到一个独立的模块中,在redux文件夹创建一个store.js的文件

import {createStore} from 'redux';
import {counter} from './reducers'; // 创建一个store对象
// createStore()的作用是创建包含指定reducer的store对象
const store = createStore(counter); // 内部会第一次调用reduer函数得到初始state
console.log(store);//store对象 export default store

修改index.js项目入口文件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import store from './redux/store' function render () {
ReactDOM.render(<App store={store} />, document.getElementById('root'));
}
render() // 初始化渲染 store.subscribe(render) // 订阅监听(store中的状态变化了就会自动调用进行重绘) // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

react-redux

上面使用redux,有一些小的问题就是:redux与react组件的代码耦合度太高,编码不够简洁,那么就有了一个插件react-redux

react-redux:一个react插件库,专门用来简化react应用中使用redux

React-Redux将所有组件分成两大类:

UI组件:只负责 UI 的呈现,不带有任何业务逻辑,通过props接收数据(一般数据和函数),不使用任何 Redux 的 API,一般保存在components文件夹下

容器组件:负责管理数据和业务逻辑,不负责UI的呈现,使用 Redux 的 API,一般保存在containers文件夹下

React-Redux相关API

Provider:这是一个组件,将这个组件包裹着App.js组件让所有组件都可以得到state数据

<Provider store={store}>
    <App />
</Provider>

connect():用于包装 UI 组件生成容器组件,就是用于react组件和redux之间的连接

mapStateToprops():将外部的数据(即state对象)转换为UI组件的标签属性

mapDispatchToProps():将分发action的函数转换为UI组件的标签属性,简洁语法可以直接指定为actions对象或包含多个action方法的对象

import { connect } from 'react-redux'
connect(
mapStateToprops,
mapDispatchToProps
)(Counter)

使用react-redux

首先需要下载安装依赖包

npm install --save react-redux

修改index.js项目入口文件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import store from './redux/store'
import {Provider} from 'react-redux' ReactDOM.render((
<Provider store={store} >
<App/>
</Provider>
), document.getElementById('root')); // If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

sotre也不需要一层层的传递了

import React from 'react';
import './App.css'; import Main from './views/main/main'
class App extends React.Component {
render() {
return (
<div className="App">
<Main/>
</div>
);
}
} export default App;

在应用组件中使用react-redux的API方法connect()来跟store进行连接

import React from 'react';
import './main.css';
import PropTypes from "prop-types";
import { connect } from 'react-redux'; import {increment, decrement} from '../../redux/actions'; class Main extends React.Component{
static propTypes = {
count: PropTypes.number.isRequired,
increment: PropTypes.func.isRequired,
decrement: PropTypes.func.isRequired
}
increment = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 因为的到的是字符串所以乘以1隐式转换成number // 2. 调用store的方法更新状态
this.props.increment(number)
}
decrement = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 2. 调用store的方法更新状态
this.props.decrement(number)
}
incrementIfOdd = ()=> {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态
const count = this.props.count
// 3. 判断当前状态如果式奇数才更新
if (count%2 === 1) {
// 4. 调用store的方法更新状态
this.props.increment(number)
}
}
incrementAsync =() => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 启动延时定时器
setTimeout(() => {
// 2. 调用store的方法更新状态
this.props.increment(number)
},1000)
}
render() {
const {count} = this.props
return (
<div className="App">
<p>click {count} times</p>
<div>
<select ref={select => this.select = select}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>increment if odd</button>
<button onClick={this.incrementAsync}>increment async</button>
</div>
</div>
);
}
} // connect是一个函数需要接收一个参数是组件类型(也就是一个对象),执行之后返回的还是一个函数,并且返回新的组件
export default connect(
state => ({count: state}),
{increment, decrement}
)(Main);

这样我们就把react-redux给使用上了,还可以在进一步优化就是将connect和组件分离出来,UI组件: 不包含任何redux API

import React from 'react';
import './main.css';
import PropTypes from "prop-types"; class Main extends React.Component{
static propTypes = {
count: PropTypes.number.isRequired,
increment: PropTypes.func.isRequired,
decrement: PropTypes.func.isRequired
}
increment = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 因为的到的是字符串所以乘以1隐式转换成number // 2. 调用store的方法更新状态
this.props.increment(number)
}
decrement = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 2. 调用store的方法更新状态
this.props.decrement(number)
}
incrementIfOdd = ()=> {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态
const count = this.props.count
// 3. 判断当前状态如果式奇数才更新
if (count%2 === 1) {
// 4. 调用store的方法更新状态
this.props.increment(number)
}
}
incrementAsync =() => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 启动延时定时器
setTimeout(() => {
// 2. 调用store的方法更新状态
this.props.increment(number)
},1000)
}
render() {
const {count} = this.props
return (
<div className="App">
<p>click {count} times</p>
<div>
<select ref={select => this.select = select}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>increment if odd</button>
<button onClick={this.incrementAsync}>increment async</button>
</div>
</div>
);
}
} export default Main

创建containters文件夹并且创建一个js文件(包含Main组件的容器组件)

import React from 'react';
import { connect } from 'react-redux'; import {increment, decrement} from '../redux/actions';
import Main from '../views/main/main' // connect是一个函数需要接收一个参数是组件类型(也就是一个对象),执行之后返回的还是一个函数,并且返回新的组件
export default connect(
state => ({count: state}),
{increment, decrement}
)(Main);
import React from 'react';
import './App.css'; import Main from './containters/main'
class App extends React.Component {
render() {
return (
<div className="App">
<Main/>
</div>
);
}
} export default App;

这样就完成了react-redux的使用,但是也有一个问题就是redux默认是不能进行异步处理的, 应用中又需要在redux中执行异步任务(ajax, 定时器)

怎么样让redux支持异步操作,请看下面:redux异步编程

redux异步编程

下载redux插件(异步中间件)

npm install --save redux-thunk

然后下redux文件夹的store.js文件中引入

import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import {counter} from './reducers'; // 创建一个store对象
// createStore()的作用是创建包含指定reducer的store对象
const store = createStore(
counter,
applyMiddleware(thunk) // 应用上异步中间件
); export default store

在actions.js中添加一个异步操作的方法

/*action creator模块*/
import {INCREMENT, DECREMENT} from './action-types' export const increment = number => ({type: INCREMENT, data: number})
export const decrement = number => ({type: DECREMENT, data: number})
export const incrementAsync = number => {
return dispatch => {
setTimeout(() => {
dispatch(increment(number))
}, 1000)
}
}

在connect()把这个action方法加进来

import React from 'react';
import { connect } from 'react-redux'; import {increment, decrement, incrementAsync} from '../redux/actions';
import Main from '../views/main/main' // connect是一个函数需要接收一个参数是组件类型(也就是一个对象),执行之后返回的还是一个函数,并且返回新的组件
export default connect(
state => ({count: state}),
{increment, decrement, incrementAsync}
)(Main);

在应用组件中通过props进行调用这个action方法

import React from 'react';
import './main.css';
import PropTypes from "prop-types"; class Main extends React.Component{
static propTypes = {
count: PropTypes.number.isRequired,
increment: PropTypes.func.isRequired,
decrement: PropTypes.func.isRequired,
incrementAsync: PropTypes.func.isRequired
}
increment = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 因为的到的是字符串所以乘以1隐式转换成number // 2. 调用store的方法更新状态
this.props.increment(number)
}
decrement = () => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 2. 调用store的方法更新状态
this.props.decrement(number)
}
incrementIfOdd = ()=> {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1
// 2. 读取原本state中的count状态
const count = this.props.count
// 3. 判断当前状态如果式奇数才更新
if (count%2 === 1) {
// 4. 调用store的方法更新状态
this.props.increment(number)
}
}
incrementAsync =() => {
// 1. 读取select中的值(选择增加的数量)
const number = this.select.value*1 // 2. 调用store的方法更新状态
this.props.incrementAsync(number)
}
render() {
const {count} = this.props
return (
<div className="App">
<p>click {count} times</p>
<div>
<select ref={select => this.select = select}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>increment if odd</button>
<button onClick={this.incrementAsync}>increment async</button>
</div>
</div>
);
}
} export default Main

使用上redux调试工具

首先安装chrome浏览器插件(直接在谷歌应用商店搜索,然后点击安装)

然后在项目中下载工具依赖包

npm install --save-dev redux-devtools-extension

修改项目中的创建store的代码中加入这个插件

import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension'
import {counter} from './reducers'; // 创建一个store对象
// createStore()的作用是创建包含指定reducer的store对象
const store = createStore(
counter,
composeWithDevTools(applyMiddleware(thunk)) // 应用上异步中间件
); export default store

Redux源码

let createStore = (reducer) => {
let state;
//获取状态对象
//存放所有的监听函数
let listeners = [];
let getState = () => state;
//提供一个方法供外部调用派发action
let dispath = (action) => {
//调用管理员reducer得到新的state
state = reducer(state, action);
//执行所有的监听函数
listeners.forEach((l) => l())
}
//订阅状态变化事件,当状态改变发生之后执行监听函数
let subscribe = (listener) => {
listeners.push(listener);
}
dispath();
return {
getState,
dispath,
subscribe
}
}
let combineReducers=(renducers)=>{
//传入一个renducers管理组,返回的是一个renducer
return function(state={},action={}){
let newState={};
for(var attr in renducers){
newState[attr]=renducers[attr](state[attr],action) }
return newState;
}
}
export {createStore,combineReducers};

redux详解的更多相关文章

  1. 从Flux到Redux详解单项数据流

    从Flux到Redux是状态管理工具的演变过程,但两者还是有细微的区别的.但是最核心的都还是观察者模式的应用. 一.Flux 1. Flux的处理逻辑 通俗来讲,应用的状态被放到了store中,组件是 ...

  2. ReactNative之Redux详解

    用redux有一段时间了,感觉还是有必要把其相关的知识点系统的总结一下的,毕竟好记性不如烂笔头.上篇博客更新了关于<ES6中的迭代器.Generator函数以及Generator函数的异步操作& ...

  3. 九、小程序 Redux详解与在小程序中怎么使用(action和reducers)

    什么是Redux ​ Redux我们可以把它理解成一个状态管理器,可以把状态(数据)存在Redux中,以便增.删.改.例如: 从服务器上取一个收藏列表,就可以把取回来的列表数据用Redux管理,多个页 ...

  4. 详解 Node + Redux + MongoDB 实现 Todolist

    前言 为什么要使用 Redux? 组件化的开发思想解放了繁琐低效的 DOM 操作,以 React 来说,一切皆为状态,通过状态可以控制视图的变化,然后随着应用项目的规模的不断扩大和应用功能的不断丰富, ...

  5. React-Navigation与Redux整合详解

    本文转自:文章地址:http://blog.csdn.net/u013718120/article/details/72357698 继react-navigation发布已经过去半年的时间,想必Re ...

  6. redux和react-redux的使用详解

    我自己的理解redux就跟vue中的vuex差不多,都是数据管理器,话不多说,我们从经典的计数器案例开始讲解 使用redux实现计数器 创建如下的react项目,我习惯把每一个模块分块,才有这么多文件 ...

  7. js对象详解(JavaScript对象深度剖析,深度理解js对象)

    js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...

  8. webpack4配置详解之新手上路初探

    前言 经常会有群友问起webpack.react.redux.甚至create-react-app配置等等方面的问题,有些是我也不懂的,慢慢从大家的相互交流中,也学到了不少. ​ 今天就尝试着一起来聊 ...

  9. vue和react全面对比(详解)

    vue和react对比(详解) 放两张图镇压小妖怪 本文先讲共同之处, 再分析区别 大纲在此: 共同点: a.都使用虚拟dom b.提供了响应式和组件化的视图组件 c.注意力集中保持在核心库,而将其他 ...

随机推荐

  1. 分布式思想和rpc解决方案介绍

    1.RPC的诞生 RPC(Remote Procedure Call)远程过程调用,通过这个rpc协议,调用远程计算机上的服务,就像调用本地的服务一样. 不同的服务部署在不同的机器上面,并且在启动后在 ...

  2. jq二级目录

    CSS:.qsc_nav_main .level1 { text-align: center; height: auto; } .qsc_nav_main .level1 a { display: i ...

  3. ASP.NET中多语言的实现

    一个网站可能具备多个语言,要实现这个功能在ASP.NET中是非常简单的.我们需要为项目添加资源文件文件夹,并且添加针对网站的特定的资源文件等即可.在ASP.NET中资源文件分成两类:全局和页面级(即“ ...

  4. 【LDAP】LDAP介绍

    原文:http://ldapman.org/articles/intro_to_ldap.html原文作者:Michael Donnelly 什么是LDAP? LDAP的英文全称是Lightweigh ...

  5. 用java实现删除文件夹里的所有文件

    package com.org.improve.contact; import java.io.File; public class DeletePaper { /** * @param args * ...

  6. ubuntu下mysql安装(server、client、dev),开启、停止和重启,及常见错误

    转自:ubuntu下mysql安装(server.client.dev),开启.停止和重启,及常见错误 1. 在ubuntu下安装server和client很简单: (1)安装server apt-g ...

  7. Fastjson中以is打头出现的问题,会生成两个变量

    解决办法: @JSONField(name = "isSelf")public boolean isSelf = false; 这样就不会生成两个谜题 self和isSelf了 h ...

  8. js报错

    1.如果出现找不到js方法,感觉写的js都正确就是调试报错,可能原因是js文件重复引用 2.在用ajax异步提交时千万别用 submit 控件,submit控件是表单提交控件,提交表单的同时不会执行异 ...

  9. canvas绘制圆环

  10. Implementation with Java

    Implementation with Java From:http://jcsc.sourceforge.net In general, follow the Sun coding conventi ...