Flux --gt; Redux --gt; Redux React 入门 基础实例教程

本文的目的很简单,介绍Redux相关概念用法 及其在React项目中的基本使用

 

假设你会一些ES6、会一些React、有看过Redux相关的文章,这篇入门小文应该能帮助你理一下相关的知识

一般来说,推荐使用 ES6+React+Webpack 的开发模式,但Webpack需要配置一些东西,你可以先略过,本文不需要Webpack基础

入门,只是一些基础概念和用法的整理,更完整的内容推荐去看看文档,英文中文

(不过我个人认为,官方文档的例子相对来说太复杂了,很难让新手马上抓住重点)

(官方的例子正统且联系业务,不同类型的操作或数据放在不同文件中,很规范,但也很绕,所以本文使用的例子非常简单,且直接放在一个文件中 以便于理解)

一、Flux

Flux是一种概念思想,或者说是一种应用架构

根据它的概念,一个应用中的数据流动应是单向的,且应用中的所有数据保存在一个位置,数据变化时保证视图也同步变化,保证了数据和视图的状态是一一对应起来的

此应用应该分为四层:

  • view层:应用的视图,页面的(数据)展示

  • action层:(视图)发出的某些动作,比如点击事件

  • dispatcher层:派发器,接收action并处理这些动作,更新数据

  • store层:存放应用的数据,数据更新后,提醒view层更新视图

它的概念思想可能一时半会理解不了,没关系,过段时间就好了

 

二、Redux

上面说到,Flux只是一个思想,我们可以根据这个思想来自己实现出一个技术方案,来解决问题

是要解决什么问题呢?

在使用React的过程中,在组件间通信的处理上我们用了回调的方式,如果组件层级很深,不同组件间的数据交流就会导致回调及其触发的函数非常多,代码冗杂

需要一个状态管理方案,方便管理不同组件间的数据,及时地更新数据

而Flux思想中的Store层,切合了这个问题

 

1. 什么是Redux

Redux是受Flux启发实现的一个技术方案,可以认为它是Flux的产物,但它并没有沿用Flux所有的思想

主要区别是Flux的派发器dispatcher,Redux认为使用派发器就得增加事件订阅/发布的规则,倒不如直接用函数调用的方式来得实在,简单而统一,所以就将处理action的任务交给了store层(直接调用这个对象的dispatch方法)

2. 什么时候用Redux

Redux说简单简单,因为也就几个API,理解好概念就好用了;说复杂也复杂,因为它将一个应用分成了不同部分(action、处理action、store数据等),在正规的项目中是推荐将各部分区分到不同文件中的(如官方的例子),文件数量很多可能会比较难管理,当然,细粒化了也就减少了耦合度。最后还要加个操作把Redux的数据更新给React组件(如果用了React)

在大多数情况下,Redux是不需要用的,如UI层非常简单,没有太多互动的

  • 用户的使用方式非常简单

  • 用户之间没有协作

  • 不需要与服务器大量交互,也没有使用 WebSocket

  • 视图层(View)只从单一来源获取数据

 

而在多交互,多数据源的时候可以考虑使用

  • 用户的使用方式复杂

  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)

  • 多个用户之间可以协作与服务器大量交互,或者使用了WebSocketView

  • 要从多个来源获取数据

在需要管理复杂组件状态的时候,可以考虑使用

  • 某个组件的状态,需要共享某个状态

  • 需要在任何地方都可以拿到一个组件

  • 需要改变全局状态一个组件

  • 需要改变另一个组件的状态

 

3. 开始用Redux

上面讲了那么多字,还是看代码来得实在

这里先纯粹讲Redux,毕竟它和React是没啥关系的

首先是环境配置,基本上都会使用ES6,所以Babel的支持是必须的

然后是Redux的支持,如果使用Webpack打包编译,就用npm安装个redux包

这里采用直接在浏览器引入的方式,使用 这个库

  <body><div id="box"></div><script type="text/javascript" src="../lib/react.js"></script><script type="text/javascript" src="../lib/react-dom.js"></script><script type="text/javascript" src="../lib/redux.min.js"></script><script type="text/javascript" src="../build/reduxStart.js"></script></body>

最后build里的为demo代码用babel编译之后的es5文件

在全局之中有Redux这个对象,取其中的几个属性来用

let {Component} = React;
let {render} = ReactDOM;
let {createStore, combineReducers} = Redux;

3.1 Redux需要一个store来存放数据

这个store就由createStore创建

3.2 需要定义各个操作是什么,即action

通常来说它是一个对象,包含type属性表示是什么操作,以及其他属性携带一些数据

它可能长这样子,建议是遵循官方的 一些规范

let upAction = {type: 'UP'};

我们不止会传type,还会传一些值,如果传不同的值就let一次就太冗杂了,一般来说就会用一个方法代替

let upAction = function(value) {    return {type: 'up',value};
};

3.3 需要定义怎么处理操作,在redux中它被称作reducer

为什么把这种操作称作reducer呢

redux引入了JS数组reduce方法的思想,JS的reduce长这样

var arr = [1, 2, 3, 4];var num = arr.reduce((a, b) => {    return a + b;
});num // 10var num = arr.reduce((a, b) => {    return a + b;
}, 5);num // 15

当然了,只是看起来像,实际上差别挺大的,redux的reducer看起来像这样

let upReducer = function(state = 0, action) {    switch (action.type) {        case 'up':            return state + action.value;        default:            return state;}
};

它是一个函数,接收两个参数,第一个参数为数据(即某个状态state),第二个参数为action操作对象

为了切合store中数据与view中视图是一一对应的,reducer规定需始终返回新的state数据,不能直接在原有state中修改

并且,建议在匹配不到action的时候始终返回默认的state状态,且建议在第一个参数中初始化默认的state值

 

3.4 在创建store的时候绑定reducer

redux基本上把所有操作都给了store,所以大部分方法都是用store来调用的

其实,你也可以认为Flux中的派发器(dispatcher)就是在里面自动绑定的

let store = createStore(reducer);// let store = createStore(reducer, 10);

如上,创建store的时候传入reducer,可以接收第二个参数表示reducer使用的默认值

3.5 视图发出action动作

在某个时刻,发出了这些动作

store.dispatch(upAction(10));
store.dispatch(upAction(100));

3.6 使用store.getState()获取store中的数据

3.7 动作发出后,reducer匹配动作更新store中的数据,视图view层使用subscribe监听数据的改变

store.subscribe(() => console.log(store.getState()));

来看一下完整的代码

let {Component} = React;
let {render} = ReactDOM;
let {createStore, combineReducers} = Redux;let upAction = function(value) {    return {type: 'up',value};
}let upReducer = function(state = 0, action) {    switch (action.type) {        case 'up':            return state + action.value;        default:            return state;}
};let store = createStore(upReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());console.log(store.getState());store.subscribe(() => console.log(store.getState()));store.dispatch(upAction(10));
store.dispatch(upAction(100));

注意上面createStore中第二个参数是用于Redux DevTool的配置,即这个东西

使用这个工具可以便于开发

看看上面代码的输出

初始获取到的值为0,两次action后分别更新相关的数据状态。如果加上初始默认值10

let store = createStore(upReducer, 10, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

 

3.8 使用多个reducer时,使用Redux的combineReducers方法

action当然不会只是up,可能是down,这时可以直接用switch语句切换;但如果action不是这里增减的操作,放在一起就有点乱套了

所以需要定义多个reducer,但createStore方法只接收一个reducer,所以就需要整合多个reducer为一个,再统一传入

它看起来像这样

let reducer = combineReducers({upReducer, downReducer});// let reducer = combineReducers({//     upReducer: upReducer, //     downReducer: downReducer// });

接收一个reducer组成的对象,属性表示该reducer对应的state名(如state.upReducer),值表示这个reducer

当然,这个方法我们可以自己定义,看起来是这样

let myCombineReducers = function(reducerObj) {let newState = {};    return function(state = {}, action) {        for (let item in reducerObj) {newState[item] = reducerObj[item](state[item], action);}        return newState;}
};

其实就是遍历reducer组,返回一个统一的新的reducer,且新的reducer中返回一个新的state

 

加上个down操作,来看看完整代码

let {Component} = React;
let {render} = ReactDOM;
let {createStore, combineReducers} = Redux;let upAction = function(value) {    return {type: 'up',value};
}
let downAction = function(value) {    return {type: 'down',value};
}let upReducer = function(state = 0, action) {    switch (action.type) {        case 'up':            return state + action.value;        default:            return state;}
};let downReducer = function(state = 0, action) {    switch (action.type) {        case 'down':            return state - action.value;        default:            return state;}
};let reducer = combineReducers({upReducer, downReducer});let store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());console.log(store.getState());store.subscribe(() => console.log(store.getState()));store.dispatch(upAction(10));
store.dispatch(upAction(100));
store.dispatch(downAction(10));
store.dispatch(downAction(100));

给reducer设个初始值,要注意的是,这个初始值是针对整个state的

如果只有一个reducer,那reducer函数中的state就是这个state

如果用combineReducer整理了多个reducer,那各个reducer函数中的state是整个state中的reducer同名属性的值

let reducer = combineReducers({upReducer, downReducer});let store = createStore(reducer, {upReducer: 10, downReducer: 10}, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

如上代码定义了初始值,看看执行结果

 

四. 在React中使用Redux

Redux是一个独立的技术方案,我们将它运用到React项目中

接下来的问题主要有三个:

  • 如何将store中的数据同步给React组件

  • 如何让React组件调用Redux的dispatch方法

  • 上面两个

直接点,就是在React组件中调用Redux的subscribe方法来监听同步数据,再在某个时机调用dispatch即可

但官方并不建议使用subscribe这个方法,而是建议使用封装好的另一个库 React-Redux

 

4.1 引入库

与引入Redux类似,你可以使用Webpack引入包或浏览器直接引入这个库

然后在全局window下可以获取到这个对象,取一些用到的属性如

let {Provider, connect} = ReactRedux;

4.2 先定义一个有增长操作的React组件

class Increase extends Component {constructor(props) {super(props);}componentWillReceiveProps(nextProps) {console.log(nextProps);}increase() {let {dispatch} = this.props;dispatch({type: 'up'});}render() {        return <p onClick={this.increase.bind(this)}>increase: {this.props.number}</p>    }
}

组件定义了一个action,即点一次执行一次增长(increase)函数,里面调用dispatch方法发出action,先看看其他东西

4.3 定义一个reducer

function couterUp(state = {number: 100}, action) {    switch (action.type) {        case 'up':            return {number: state.number + 1};        default:            return state;}
}

4.4 创建一个store

let store = createStore(couterUp, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

4.4 使用ReactRedux的connect方法

要将Redux中的数据同步给React,需要用到这个方法

它看起来像是这样子

let APP = connect(mapStateToProps,mapDispatchToProps
)(Increase);

可以把它看成是一个中间件,首先接收几个参数完成配置阶段,然后传入React组件,包装成一个新的东东(它并没有直接修改Increase组件)

而一般来说,一般来说会传入两个参数(支持四个参数),顾名思义:

第一个参数(类型为函数)

如果不传或置入undefinednull,则表示不需要进行数据更新;否则表示将store中的数据通过props的形式传给React组件

第二个参数(类型为函数)

如果不传或置入undefinednull,则表示将React-Redux中默认的dispatch方法传给React组件;否则表示将redux中的dispatch发出动作通过props的形式传给React组件

注意到上面的React组件代码中,通过props获取到了dispatch方法,然后自行发出动作

  increase() {let {dispatch} = this.props;dispatch({type: 'up'});}

如果要这样做,mapDispatchToProps 这里就不传入了,即

let APP = connect(mapStateToProps
)(Increase);

用回常见的方式,在React组件中改一改,直接从props中获取某个dispatch的发出动作

render() {        return <p onClick={this.props.increase}>increase: {this.props.number}</p>}

同时修改两个都传入

let APP = connect(mapStateToProps,mapDispatchToProps
)(Increase);

4.5 mapStateToProps 和 mapDispatchToProps

我们定义一下这两个参数(函数),它看起来长这样

function mapStateToProps(state) {    return {number: state.number};
}function mapDispatchToProps(dispatch) {    return {increase: () => dispatch({type: 'up'})};
}

mapStateToProps 中第一个参数为一个对象,表示store中整体的state数据

当然,第一个参数也可以为函数,也可以接收第二个参数,表示自身拥有的属性(ownProps),具体可以看API

最后它返回了一个新的对象,表示要传给React组件的数据

与mapStateToProps类似,mapDispatchToProps 也可以接收两个参数,

第一个表示当前的dispatch方法,第二个表示自身拥有的 propsDispatch方法(即类似省略参数传给字组件的默认dispatch方法)

最后它返回了一个action发出动作(一个函数),传给React组件调用

 

4.6 使用Provider

基本好了,只差一步:将connect包装组件后生成的新东东与实际页面联系起来

使用ReactRedux提供的<Provider />,它看起来是这样

render(    <Provider store={store}><APP /></Provider>,document.getElementById('box')
);

使用store属性传入上面的store对象

在children中置入有connect生成的APP组件,注意这里只能包含一个父层

如果向其中传入属性,如

<APP name="app" />

那么,mapStateToProps中的第二参数ownProps就可以拥有这个name属性

看一下运行结果

4.7 多个React组件中的使用

上面说的是单个React组件中的使用,实际使用中会有多个组件

多个组件的使用类似单个,只不过需要注意两点

  • <Provider />中只能包含一个父级

  • mapStateToProps中第一个参数是指整体store中的数据

下面以两个组件的栗子,看看如何实现

 

4.7.1 首先定义两个组件,一增一减

class Increase extends Component {constructor(props) {super(props);}componentWillReceiveProps(nextProps) {console.log('increase: ', nextProps);}render() {return <p onClick={this.props.increase}>increase: {this.props.number}</p>}
}class Decrease extends Component {constructor(props) {super(props);}componentWillReceiveProps(nextProps) {console.log('decrease: ', nextProps);}render() {return <p onClick={this.props.decrease}>decrease: {this.props.number}</p>}
}

4.7.2 定义对应的两个reducer

function couterUp(state = {number: 100}, action) {    switch (action.type) {        case 'up':            return {number: state.number + 1};        default:            return state;}
}function counterDown(state = {number: -100}, action) {    switch (action.type) {        case 'down':            return {number: state.number - 1};        default:            return state;}
}

4.7.3 创建store

let couter = combineReducers({couterUp,counterDown
});let store = createStore(couter,{couterUp: {number: 10}},window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

4.7.4 创建连接两个组件对应的两个mapStateToProps 和 mapDispatchToProps

注意state为整个store中的state,取值要取各reducer同名属性如 state.couterUp

function mapStateToProps_1(state) {    return {number: state.couterUp.number};
}function mapDispatchToProps_1(dispatch) {    return {increase: () => dispatch({type: 'up'})};
}function mapStateToProps_2(state, props) {    return {number: state.counterDown.number};
}function mapDispatchToProps_2(dispatch) {    return {decrease: () => dispatch({type: 'down'})};
}

4.7.5  各组件用connect包装

let APP_1 = connect(mapStateToProps_1,mapDispatchToProps_1
)(Increase);let APP_2 = connect(mapStateToProps_2,mapDispatchToProps_2
)(Decrease);

4.7.6  置入<Provider />中

注意只能有一个父级,所以得先简单包装一层

let APP = () => (    <div><APP_1 /><APP_2 name="APP_2"/></div>);render(    <Provider store={store}><APP /></Provider>,document.getElementById('box')
);

Good ! 完成了,看看结果

 

4.7.7  再看connect方法剩余的两个参数

connect方法接收可接收四个参数,上面已经谈到了前两个,后两个不那么常用

第三个参数,这里不多说:[mergeProps(stateProps, dispatchProps, ownProps): props] (Function)

第四个参数[options(Object)

这个options中有如下几个属性:

  • pure: true(默认)|false 表示是否在调用connect前三个参数的函数方法之前先检测前后store中的值是否改变,改变才调用,否则不调用

  • areStatesEqual: 函数,当pure为true时调用这个函数检测是否相等,返回true|false表示是否相等,默认以严格相等===来判断前后值是否相等

  • areOwnPropsEqual: 类似areStatesEqual,只不过它默认是用不严格相等==来判断

  • areStatePropsEqual: 类似areStatesEqual,只不过它默认是用不严格相等==来判断

  • areMergedPropsEqual: 类似areStatesEqual,只不过它默认是用不严格相等==来判断

来看个例子,现在要手动的定义这个参数

针对Decrease,在减1时直接返回了false

let APP_2 = connect(mapStateToProps_2,mapDispatchToProps_2,    null,{pure: true,areStatesEqual: (next, prev) => {console.log(next.counterDown, prev.counterDown);            return next.counterDown.number < prev.counterDown.number;}}
)(Decrease);


可以看到,减1的操作并没有传给Decrease组件,页面没有更新

 

顺便看看有connect包装后的组件

 

4.7.8 在React-Redux中使用异步

因Redux中操作的执行是同步的,如果要实现异步,比如某个操作用来发个异步请求获取数据,就得引入中间件来处理这种特殊的操作

即这个操作不再是普通的值,而是一个函数(如Promise异步),通过中间件的处理,让Redux能够解析 

先修改上面的栗子,在Increase组件中不再是每次增加1,而是根据action中的value来指定,比如

function mapDispatchToProps_1(dispatch) {    return {increase: () => dispatch({type: 'up',value: 10})};
}
function couterUp(state = {number: 100}, action) {    switch (action.type) {        case 'up':            return {                // number: state.number + 1number: state.number + action.value};        default:            return state;}
}

这里定义了value是10,但假如value的值得由一个异步的请求才得出呢,要如何放进去

 

使用Redux提供的中间件applyMiddleware

let {createStore, combineReducers, applyMiddleware} = Redux;

这只是基础的中间件apply函数,它帮助Redux将中间件包装

现在来模拟一个异步请求

function mapDispatchToProps_1(dispatch) {    return {        // increase: () => dispatch({//     type: 'up',//     value: 10// })increase: () => dispatch(fetchIncreaseValue('redux-ajaxTest.php'))};
}

可一看到,dispatch中的action是一个函数(这个调用返回的还是一个函数),而Redux默认只支持对象格式的action,所以这样会报错

这里的fetchIncreaseValue看起来像这样

function fetchIncreaseValue(url) {    return function(dispatch) {        return $.get(url).then(re => {re = JSON.parse(re);console.log(re);dispatch({type: 'up',value: re.value});})}
}

而请求后台后返回值

<?php    echo json_encode(array('value' => 100));?>

可以看到,异步获取数据之后才执行dispatch发出操作,这里需要一个dispatch关键字

为了拿到这个关键字,得和thunkMiddleware搭配使用(让这个方法能够在内层函数中使用),当然,你也可以再搭配其他中间件

如果使用Webpack打包,就安装好 redux-thunk 包再 import 进来

这里直接引入到浏览器中,引入这个库,然后直接使用(注意这里没有 {} )

let thunkMiddleware = window.ReduxThunk.default;

然后在创建store的时候,传给redux的applyMiddleware即可

let store = createStore(couter,{couterUp: {number: 10}},applyMiddleware(thunkMiddleware),window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);


官方给的例子太复杂了,不过还是去看看吧,我这里抽出了主要的部分,

先来看看结果

 

使用这个Redux Dev Tool就得在createStore中配上最后一个参数,而createStore自身的某个参数又能给reducer设置初始值,且applyMiddleware也是在参数中定义

所以要注意的是:

如果用了这个Redux Dev Tool,就要保证applyMiddleware在第三个参数


let store = createStore(couter,
  // {},applyMiddleware(thunkMiddleware),window.__REDUX_DEVTOOLS_EXTENSION__
&& window.__REDUX_DEVTOOLS_EXTENSION__() );

类似这样省略第二个初始值参数,是会报错的

把注释去掉,放上一个空的初始即可,或者不用这个Dev Tool

let store = createStore(couter,applyMiddleware(thunkMiddleware)
);

可以去看看其他的Dev Tool

原文地址:http://www.cnblogs.com/imwtr/p/6327384.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/327081.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mybatisplus 强制制空 空覆盖原来的字符串

ApiModelProperty(value "证件照片url") TableField(value "id_photo_url",fill FieldFill.UPDATE) private String idPhotoUrl; 方法一 Data EqualsAndHashCode(callSuper false) Accessors(chain true) TableName("base_party_member") A…

微软开源Visual Studio测试平台VSTest

IT之家1月21日消息 微软在MSDN博客上宣布&#xff0c;开源旗下Visual Studio测试平台VSTest。这一平台是具备高扩展性的单元测试执行框架&#xff0c;能够在不同的核心之间实现并行化&#xff0c;提供进程隔离&#xff0c;并能够整合进Visual Studio。 目前&#xff0c;VSTest能…

线程的状态与调度

当我们使用new关键字新建一个线程&#xff0c;这个时候线程就进入了新建状态&#xff08;New&#xff09;&#xff0c;也就是图中未启动状态&#xff1b;调用start方法启动线程&#xff0c;这个时候就进入了可运行状态&#xff0c;也就是就绪状态&#xff08;Runnable&#xff…

深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题

转载自 深入JVM系列&#xff08;三&#xff09;之类加载、类加载器、双亲委派机制与常见问题 一&#xff0e;概述 定义&#xff1a;虚拟机把描述类的数据从Class文件加载到内存&#xff0c;并对数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的java…

Fabio 安装和简单使用

Fabio&#xff08;Go 语言&#xff09;&#xff1a;https://github.com/eBay/fabio Fabio 是一个快速、现代、zero-conf 负载均衡 HTTP(S) 路由器&#xff0c;用于部署 Consul 管理的微服务。 Fabio 由 eBay Classifieds Group 开发&#xff0c;用于处理 marktplaats.nl 和 kij…

计算密集型分布式内存存储和运算平台架构

1. 相关概念 1.1 内存数据库 关系型数据库处理永久、稳定的数据&#xff0c;内存数据库就是将其数据放在内存中&#xff0c;活动事务只与内存数据打交道&#xff0c;重新设计了体系结构并且在数据缓存、快速算法、并行操作方面也进行了相应的改进&#xff0c;所以数据处理速度比…

【深入Java虚拟机】之四:类加载机制

转载自 【深入Java虚拟机】之四&#xff1a;类加载机制 类加载过程 类从被加载到虚拟机内存中开始&#xff0c;到卸载出内存为止&#xff0c;它的整个生命周期包括&#xff1a;加载、验证、准备、解析、初始化、使用和卸载七个阶段。它们开始的顺序如下图所示&#xff1a; 其中…

违反ClassLoader双亲委派机制三部曲第二部——Tomcat类加载机制

转载自 违反ClassLoader双亲委派机制三部曲第二部——Tomcat类加载机制 前言&#xff1a; 本文是基于 ClassLoader双亲委派机制源码分析 了解过正统JDK类加载机制及其实现原理的基础上&#xff0c;进而分析这种思想如何应用到Tomcat这个web容器中&#xff0c;从源码的角度对 违…

红包的技术升级之旅

鸡年春节&#xff0c;红包再次成为年味儿最重要的催化剂。先是腾讯QQ钱包推出“LBSAR天降红包”等三种创新有趣的玩法&#xff0c;支付宝上线AR实景红包&#xff0c;微博亦推出视频红包等形式。虽然微信退出红包营销让人稍有意外&#xff0c;但用户对红包的热情仍未消减。 事实…

java中生成1000~10000之间的随机数

要生成在[min,max]之间的随机整数&#xff0c;可使用Random类进行相关运算&#xff1a; Random random new Random(); int s random.nextInt(max)%(max-min1) min; random.nextInt(max)表示生成[0,max]之间的随机数&#xff0c;然后对(max-min1)取模。 以生成[1000,10000]…

C# 7.0新功能

下面是对C#7.0 版本所有语言功能的描述。随着 Visual Studio “15” preview 4 的发布&#xff0c;大部分功能可以被更灵活的应用。现在正是时候将这些功能介绍给大家&#xff0c;你也可以借此让我们知道你的想法。 C#7.0 增加了很多新的功能&#xff0c;更专注于数据的消费&am…

MybatisPlus学习(四)条件构造器Wrapper方法详解

https://www.cnblogs.com/xianz666/p/13857733.html MybatisPlus学习&#xff08;四&#xff09;条件构造器Wrapper方法详解 文章目录 1、条件构造器2、QueryWrapper 2.1、eq、ne2.2、gt、ge、lt、le2.3、between、notBetween2.4、like、notLike、likeLeft、likeRight2.4、isN…

使用ueditor实现多图片上传案例

UEditor是由百度WEB前端研发部开发的所见即所得的开源富文本编辑器&#xff0c;具有轻量、可定制、用户体验优秀等特点。开源基于BSD协议&#xff0c;所有源代码在协议允许范围内可自由修改和使用。百度UEditor的推出&#xff0c;可以帮助不少网站开发者在开发富文本编辑器所遇…

自定义ClassLoader和双亲委派机制

转载自 自定义ClassLoader和双亲委派机制 ClassLoader ClassLoad&#xff1a;类加载器&#xff08;class loader&#xff09;用来加载 Java 类到 Java 虚拟机中。Java 源程序&#xff08;.java 文件&#xff09;在经过 Java 编译器编译之后就被转换成 Java 字节代码&#xff0…

ASP.NET Core 1.0 开发记录

ASP.NET Core 1.0 更新比较快&#xff08;可能后面更新就不大了&#xff09;&#xff0c;阅读注意时间节点&#xff0c;这篇博文主要记录用 ASP.NET Core 1.0 开发简单应用项目的一些记录&#xff0c;以备查阅。 ASP.NET Core 1.0 相关 Nuget 程序包源&#xff1a;https://api.…

深入浅出ClassLoader

转载自 深入浅出ClassLoader 你真的了解ClassLoader吗&#xff1f; 这篇文章翻译自zeroturnaround.com的 Do You Really Get Classloaders? &#xff0c;融入和补充了笔者的一些实践、经验和样例。本文的例子比原文更加具有实际意义&#xff0c;文字内容也更充沛一些&#xf…

微软任命LinkedIn高级副总裁为首席技术官

Kevin Scott曾是LinkedIn工程方面的高级VP&#xff0c;被任命为微软CTO后&#xff0c;Scott将全面统筹微软战略规划&#xff0c;以主动的姿态推进公司间合作&#xff0c;以最大化微软在伙伴及客户间的影响力。据了解&#xff0c;该职位为新创职位&#xff0c;为微软公司级CTO&a…

jQuery 基础教程 (三)之jQuery的选择器

一、jQuery 选择器 &#xff08;1&#xff09;选择器是 jQuery 的根基, 在 jQuery 中, 对事件处理, 遍历 DOM 和 Ajax 操作都依赖于选择器 &#xff08;2&#xff09;jQuery 选择器的优点: 简洁的写法 $(#id) //documnet.getElementById(id); $(p) //documnet.getEl…

SQL Server 2014内存优化表的使用场景

最近一个朋友找到走起君&#xff0c;咨询走起君内存优化表如何做高可用的问题 大家知道&#xff0c;内存优化表是从SQL Server 2014开始引入&#xff0c;可能大家对内存优化表还是比较陌生&#xff0c;网上也鲜有内存优化表使用场景的文章 朋友公司做的业务是跟蜂鸟配送类似的配…