从无到有一步一步创建一个react-redux、redux-thunk使用教程:本教程GitHub地址:
https://github.com/chunhuigao/react-redux-thunk
创建react工程
在电脑上找一个文件夹,在命令窗使用create-react-app 创建我的react工程;这一步应该会的
create-react-app study-redux
复制代码
看到下面这个图证明我创建完毕
启动react服务
在创建任务完成后进入我的创建的react工程,然后npm start运行,接着在浏览器 http://localhost:3000/我应用该可以看到下面图片的场景
安装redux
要使用redux我需要使用npm将redux包安装到我的react工程中
在react工程的命令窗输入
npm install redux
npm install react-redux
npm install redux-thunk
复制代码
如果报错,请使用淘宝代理cnpm安装。等待安装完毕,从新npm start启动项目
我的工程目录
删除无用的代码
将app.js中html结构代码删除,代码如下:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
"App">
{/* "App-header">
"App-logo" alt="logo" />
Edit src/App.js
and save to reload.
"App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
*/}
);
}
}
export default App;
复制代码
这段代码对我学习redux没什么用,我喜欢代码简洁一点,所以删除了
创建第一个组件
在工程目录src/component中创建一个名为hello的文件夹,在hello文件夹中创建一个名为hello.js的文件。
在hello.js写如下代码:
import React, { Component } from 'react'
class Hello extends Component {
render() {
return (
学习redux
)
}
}
export default Hello
复制代码
在app.js中引入hello这个组件
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Hello from './component/hello/hello.js'
class App extends Component {
render() {
return (
"App">
);
}
}
export default App;
复制代码
在浏览器中我应该可以看到“学习redux”这句文案了。
添加第一个事件
给hello添加一个按钮,点击按钮可以改变“学习redux”这句文案;hello.js具体代码如下:
import React, { Component } from 'react'
import './hello.css'
class Hello extends Component {
constructor(props){
super(props)
this.state = {
title:'学习redux'
}
}
changeTitle(){
let title = '学习redux' + Math.ceil(Math.random()*100)
this.setState({
title:title
})
}
render() {
return (
{this.state.title}
)
}
}
export default Hello
复制代码
开始使用redux
下面这个流程刚开始接触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 { Provider } from 'react-redux' //新引入
import {createStore} from 'redux' //新引入
import rootReducer from './rootReducer.js' //新引入
const store = createStore(rootReducer)
ReactDOM.render(
, 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: http://bit.ly/CRA-PWA
serviceWorker.unregister();
复制代码
redux和react-redux之前安装过,引用后会报错,原因是引入的rootReducer.js这个文件需要创建;
创建rootReducer
在src文件夹创建rootReducer.js文件代码如下:
文件中combineReducers将拆分的页面单独reducer合并为一个大的reducer
import {combineReducers} from 'redux'
import helloReducer from './component/hello/helloReducer.js'
const rootReducer = combineReducers({
helloReducer
})
export default rootReducer
复制代码
这里面引入了一个helloReducer.js,这里我在hello.js同级文件夹创建helloReducer.js
创建helloReducer.js
reducer里面定义页面初始数据,在根据action.type操作state;具体代码如下:
const initState = {
name:'hello,redux'
}
export default (state=initState,action) => {
switch (action.type) {
case 'CHANGE_NAME':
return {...state,name:action.text}
default:
return state;
}
}
复制代码
然后将reducer数据绑定到组件中,这里需要用到react-redux中的connect函数
数据绑定到组件
这部分是在hello.js中进行的;具体代码如下:
import React, { Component } from 'react'
//引用connect
import {connect} from 'react-redux'
import './hello.css'
class Hello extends Component {
constructor(props){
super(props)
this.state = {
title:'学习redux'
}
}
changeTitle(){
let title = '学习redux' + Math.ceil(Math.random()*100)
this.setState({
title:title
})
}
render() {
//此处打印this.props应该可以看到helloProp这个对象了,证明数据已经挂在到组件紫红
console.log(this.props)
let {prop} = this.props
return (
{this.state.title}
我是来自redux数据{prop.name}
)
}
}
//mapStateToProps是connect一个参数, 作用到将store中的数据作为 props 绑定到组件上
const mapStateToProps = (state, ownProps) => {
return {
helloProp: state.helloReducer//helloReducer是在rootReducer中的名
}
}
//通过connect高阶函数绑定数据
export default connect(mapStateToProps)(Hello)
复制代码
数据已经绑定到组件了,怎么操作改变数据呢?需要用到action了
创建helloAction.js
在hello.js同级不目录创建helloAction.js;action主要负责发出动作指令,定义所有事件行为的;具体代码如下:
const helloAction = {
changeName:(text)=>({
type:"CHANGE_NAME",
text:text,
mate:'用于改变helloReducer中name值'
})
}
export default helloAction
复制代码
文件创建好怎么用呢?数据可以绑定到组件,action也是可以绑定到组件的,使用redux中bindActionCreators,具体代码看hello.js
将action绑定到组件
在hello.js引入新创建的helloAction.js,哎,看代码吧
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
//引入helloAction
import helloAction from './helloAction.js'
import './hello.css'
class Hello extends Component {
constructor(props){
super(props)
this.state = {
title:'学习redux'
}
}
changeTitle(){
let title = '学习redux' + Math.ceil(Math.random()*100)
this.setState({
title:title
})
}
render() {
//此处打印,应该可以看到actions
console.log(this.props)
let {prop} = this.props
return (
{this.state.title}
我是来自redux数据{prop.name}
)
}
}
const mapStateToProps = (state, ownProps) => {
return {
prop: state.helloReducer
}
}
//使用mapDispatchToProps绑定helloAction
const mapDispatchToProps = (dispatch, ownProps) => {
return {
actions:bindActionCreators(helloAction,dispatch)
}
}
//将mapDispatchToProps作为参数给connect
export default connect(mapStateToProps,mapDispatchToProps)(Hello)
复制代码
改写changeTitle事件,修改redux传过来的数据
changeTitle(){
let title = '学习redux' + Math.ceil(Math.random()*100)
// this.setState({
// title:title
// })
let {actions} = this.props
actions.changeName(title)
}
复制代码
效果图
孤例不为证,这个是在hello.js操作helloReducer的数据,不需要redux这么麻烦也可以搞定。下面我使用redux操作一下其他组件修改HelloReducer中的数据
移步GitHub点个start
创建other组件
在component文件夹中创建other文件夹,在other文件夹创建other.js;具体代码如下图
在app.js引入other.js
import React, { Component } from 'react';
import Hello from './component/hello/hello.js'
import Other from './component/other/other.js'
import './App.css';
class App extends Component {
render() {
return (
"App">
);
}
}
export default App;
复制代码
other具体代码
import React, { Component } from 'react'
import {bindActionCreators} from 'redux'
import {connect} from 'react-redux'
import helloAction from '../hello/helloAction.js'
class Other extends Component {
changeName(){
let {helloAction} = this.props;
let text = 'other' + (Math.random() *100)
helloAction.changeName(text)
}
render() {
let {otherProp} = this.props
console.log(this.props)
return (
我是其他组件
)
}
}
const mapStateToProps = (state, ownProps) => {
return {
otherProp: state.helloReducer
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
helloAction:bindActionCreators(helloAction,dispatch)
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Other)
复制代码
点击按钮,同样可以操作helloReducer.js的数据,mapStateToProps只能绑定一个数据源吗?如果other也有reducer怎么办呢?
组件上绑定多个数据
在other.js同级目录创建otherReducer.js具体代码如下:
const initState = {
title:'我是otherReducer数据'
}
export default (state=initState,action) => {
switch (action.type) {
case "CHANGE_TITLE":
return {...state,title:action.text}
default:
return state
}
}
复制代码
在rootReducer.js中引用otherReducer.js,rootReducer代码如下:
import {combineReducers} from 'redux'
import helloReducer from './component/hello/helloReducer.js'
import otherReducer from './component/other/otherReducer.js'
const rootReducer = combineReducers({
helloReducer,
otherReducer
})
export default rootReducer
复制代码
在other.js的mapStateToProps中绑定reducer数据
const mapStateToProps = (state, ownProps) => {
return {
helloProp: state.helloReducer,
otherProp: state.otherReducer
}
}
复制代码
在render打印this.props试试?
render() {
let {helloProp,otherProp} = this.props
console.log(this.props)
return (
我是其他组件
{otherProp.title}
)
}
复制代码
到此,可以使用redux了。但这写只能执行同步操作,异步操作需要要结合redux-thunk或者redux-saga了;
redux异步操作
也是写一个简单的例子
在index.js引入redux-thunk
//注释import {createStore} from 'redux'
//新增
import {createStore,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
//注释 const store = createStore(rootReducer)
//新增
const store = createStore(rootReducer,applyMiddleware(thunk))
复制代码
在component文件夹下创建example文件夹,在example文件夹创建example.js、exampleAction.js、exampleReducer.js具体代码如下:
example.js代码:
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import exampleAction from './exampleAction.js'
class Example extends Component {
asyncFn(){
let {exampleAction} = this.props
exampleAction.asyncThing()
console.log(this.props)
}
render() {
let {exampleProp} = this.props
return (
异步操作
{exampleProp.text}
)
}
}
const mapStateToProps = (state, ownProps) => {
return {
exampleProp: state.exampleReducer
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return {
exampleAction:bindActionCreators(exampleAction,dispatch)
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Example)
复制代码
exampleReducer.js代码:
const initState={
text:'我是用来测试异步操作的',
sign:null
}
export default (state=initState,action) =>{
console.log(action)
switch (action.type) {
case 'SUCCESS':
return {...state,text:action.text,sign:'success'}
case 'ERROR':
return {...state,text:action.text,sign:'error'}
default:
return state
}
}
复制代码
exampleAction.js
const exampleAction = {
asyncThing:()=>{
return (dispatch, getState) =>{
// fetch('https://hacker-news.firebaseio.com/v0/jobstories.json')
// .then(res => {
// dispatch(exampleAction.asyncSuccess('我是成功回调'))
// }).catch(e => {
// dispatch(exampleAction.asyncError('我是成功回调'))
// });
setTimeout(() => {
let sign = Math.random() >= 0.5 ? true : false;
console.log(sign)
sign ? dispatch(exampleAction.asyncSuccess('我是成功数据')) : dispatch(exampleAction.asyncError('我是失败数据'))
}, 2000);
}
},
asyncSuccess:(text)=>({
type:'SUCCESS',
text:text,
mate:'异步成功操作'
}),
asyncError:(text)=>({
type:'ERROR',
text:text,
mate:'异步成功操作'
})
}
export default exampleAction
复制代码
exampleReducer.js同样需要引入rootReduder.js中。
rootReducer代码:
import {combineReducers} from 'redux'
import helloReducer from './component/hello/helloReducer.js'
import otherReducer from './component/other/otherReducer.js'
import exampleReducer from './component/example/exampleReducer.js'
const rootReducer = combineReducers({
helloReducer,
otherReducer,
exampleReducer
})
export default rootReducer
复制代码
在app.js引入新建是example组件,应该可以看待如下界面
redux异步搞定了。
结束语:
不知我描述的清楚不清楚,希望这篇文章能不能帮到你。本人学识有限,如有文档中不规范或者误人子弟的错误言论,请指正。感谢你花时间阅读这篇文章,谢谢!