下面是如何用RxJS实现Redux Form的完整攻略。
简介
Redux Form 是用于 React 应用程序的可扩展表单组件和验证解决方案。而 RxJS 是一个用于处理异步操作的库,它的出现极大的简化了复杂异步操作的代码。
如何用 RxJS 实现 Redux Form
下面按照步骤来介绍如何用 RxJS 实现 Redux Form。
第一步:安装依赖
首先需要安装以下几个依赖:
npm install rxjs redux-react-form
第二步:创建 Observable
接着需要创建一个 Observable,用来监听Redux Form表单中的更改。可以使用RxJS提供的 fromEvent
将 onChange
事件转变为 Observable。示例如下:
import { fromEvent } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';
const inputChange$ = fromEvent(document.querySelector('#input'), 'change')
.pipe(
map(e => e.currentTarget.value),
debounceTime(500)
);
上面的代码中,map
操作符会将值从事件对象的 e.currentTarget.value
提取并传递给下一个操作符。而 debounceTime
则会等待500毫秒的时间来防止过多的事件触发。这是一个简单的Observable,现在,我们需要将它连接到Redux的Store。
第三步:连接到 Redux Store
对于简单的应用,我们可以使用 redux-observable
模块简单地将 Observable 与 Redux Store 连接起来。示例如下:
import { applyMiddleware, createStore } from 'redux';
import { createEpicMiddleware, combineEpics } from 'redux-observable';
// action 类型
const INPUT_CHANGE = 'INPUT_CHANGE';
// action creators
const inputChange = value => ({ type: INPUT_CHANGE, value });
// 这个 reducer 很简单,只是把 state 绑定到了 action 的值上。
const reducer = (state = '', action) => {
switch (action.type) {
case INPUT_CHANGE:
return action.value;
default:
return state;
}
}
// epic
const inputEpic = () => inputChange$.pipe(map(inputChange));
const rootEpic = combineEpics(
inputEpic
);
// 启动 Redux
const epicMiddleware = createEpicMiddleware(rootEpic);
const store = createStore(reducer, applyMiddleware(epicMiddleware));
这里使用了 createEpicMiddleware
创建了一个中间件,用于将 Observable 与 Redux Store 连接起来。inputEpic
是一个简单的 Epic,用于把从 inputChange$
中拿到的值封装成 Redux Action。
第四步:将组件连接到 Store
最后一步是将组件连接到Redux Store。这里我们可以使用 React Redux 提供的 connect
方法,将 Redux Store 中的值传递给组件的 props
。
import { connect } from 'react-redux';
class Input extends Component {
render() {
const { value, dispatch } = this.props;
return (
<input
type="text"
value={value}
onChange={e => dispatch(inputChange(e.target.value))}
/>
)
}
}
const mapStateToProps = state => ({
value: state
});
export default connect(mapStateToProps)(Input);
现在,我们可以在组件中使用 Observable 和 Redux Store 来管理表单的更改。
示例说明
下面给出两个示例,一个是简单表单的实现,一个是带验证的表单实现。
简单表单示例
这个示例只是用来演示如何用 RxJS 实现 Redux Form 的,所以只有一个简单的输入框。
import React from 'react';
import { fromEvent } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';
import { applyMiddleware, createStore } from 'redux';
import { createEpicMiddleware, combineEpics } from 'redux-observable';
import { connect, Provider } from 'react-redux';
// action 类型
const INPUT_CHANGE = 'INPUT_CHANGE';
// action creators
const inputChange = value => ({ type: INPUT_CHANGE, value });
// 这个 reducer 很简单,只是把 state 绑定到了 action 的值上。
const reducer = (state = '', action) => {
switch (action.type) {
case INPUT_CHANGE:
return action.value;
default:
return state;
}
}
// 这个 observable 监听了输入框的更改事件
const inputChange$ = fromEvent(document.querySelector('#input'), 'change')
.pipe(
map(e => e.currentTarget.value),
debounceTime(500)
);
// epic
const inputEpic = () => inputChange$.pipe(map(inputChange));
const rootEpic = combineEpics(
inputEpic
);
// 启动 Redux
const epicMiddleware = createEpicMiddleware(rootEpic);
const store = createStore(reducer, applyMiddleware(epicMiddleware));
// 这个组件渲染一个输入框
class Input extends React.Component {
render() {
const { value, dispatch } = this.props;
return (
<input
type="text"
value={value}
onChange={e => dispatch(inputChange(e.target.value))}
/>
)
}
}
// mapStateToProps 用于将 store 中的 state 映射到 props 中
const mapStateToProps = state => ({
value: state
});
// 这里使用了 connect 来将组件与 Redux Store 连接起来
const InputContainer = connect(mapStateToProps, null)(Input);
// 渲染组件及 Provider
ReactDOM.render(
<Provider store={store}>
<InputContainer />
</Provider>,
document.getElementById('root')
);
带验证的表单示例
在这个示例中,我们对前面的示例进行改进,增加了对表单内容的验证。示例包含一个只接受数字和字母,长度为6的字符串的输入框。
import React from 'react';
import { fromEvent } from 'rxjs';
import { map, debounceTime } from 'rxjs/operators';
import {
createStore,
applyMiddleware,
combineReducers
} from 'redux';
import {
createEpicMiddleware,
combineEpics
} from 'redux-observable';
import { connect, Provider } from 'react-redux';
// action types
const INPUT_CHANGE = 'INPUT_CHANGE';
const VALIDATION_ERROR = 'VALIDATION_ERROR';
// action creators
const inputChange = value => ({
type: INPUT_CHANGE,
value
});
const validationError = error => ({
type: VALIDATION_ERROR,
error
});
// reducer
const inputReducer = (state = '', action) => {
switch (action.type) {
case INPUT_CHANGE:
return action.value;
default:
return state;
}
}
const errorReducer = (state = '', action) => {
switch (action.type) {
case VALIDATION_ERROR:
return action.error;
default:
return state;
}
}
const rootReducer = combineReducers({
input: inputReducer,
error: errorReducer
});
// 验证函数
const validate = value => {
const pattern = /^[0-9a-zA-Z]{6}$/;
if (pattern.test(value)) {
return null;
} else {
return '内容必须是不超过6位的数字或字母';
}
}
// 观察验证错误的Observable
const validationError$ = fromEvent(document.querySelector('#input'), 'input')
.pipe(
map(e => e.target.value),
debounceTime(500),
map(validate),
map(errorMsg => validationError(errorMsg))
);
// 将两个 Observable 合并起来
const inputEpic = () => inputChange$.pipe(map(inputChange));
const epic = combineEpics(
inputEpic,
() => validationError$
);
// 启动 Redux
const epicMiddleware = createEpicMiddleware();
const store = createStore(rootReducer, applyMiddleware(epicMiddleware));
epicMiddleware.run(epic);
// 渲染组件
class Input extends React.Component {
render() {
const { input, error, dispatch } = this.props;
return (
<div>
<input
id="input"
type="text"
value={input}
onChange={e => dispatch(inputChange(e.target.value))}
/>
<div style={{color: 'red'}}>{error}</div>
</div>
)
}
}
// 将 state 映射到 props
const mapStateToProps = state => ({
input: state.input,
error: state.error
});
// 将组件与 Redux Store 连接起来
const InputContainer = connect(mapStateToProps, null)(Input);
// 渲染
ReactDOM.render(
<Provider store={store}>
<InputContainer />
</Provider>,
document.getElementById('root')
);
在上面的示例代码中,validate
函数用于验证字符串是否符合规则,返回验证错误信息(如果有)。validationError$
Observable 监听了输入框的 input
事件,然后通过 validate
函数验证输入框中的内容。如果内容不合法,则将错误信息封装为一个 Redux Action 并发出。最后,在创建 Epic 时,我们将 inputEpic
和 validationError$
合并,这样我们可以将表单内容和验证错误信息都传递给 Redux Store,最终渲染到 UI 上。
以上就是如何使用 RxJS 实现 Redux Form 的攻略,希望能对你有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:如何用RxJS实现Redux Form - Python技术站