例子来源于网上的视频教程,总结一下。
下载redux npm i redux
import {
createStore} from 'redux';
import {
countReducers} from './countReducers'
export default createStore(countReducers);
export const countReducers = (preState=0,action) =>{
switch(action.type){
case 'add' :
return preState + action.data*1;
case 'sub' :
return preState - action.data*1;
default :
return preState
}
}
import React, {
Component } from 'react';
import store from './redux/store';
export default class App extends Component {
state={
selectValue : 1
}
//加
add = () =>{
const {
selectValue} = this.state;
store.dispatch({
type:'add',data:selectValue});
}
//减
sub = () =>{
const {
selectValue} = this.state;
store.dispatch({
type:'sub',data:selectValue});
}
//异步加
asyncAdd = () =>{
const {
selectValue} = this.state;
setTimeout(() => {
store.dispatch({
type:'add',data:selectValue});
}, 1000);
}
//奇数加
oddAdd = () =>{
const {
selectValue} = this.state;
const count = store.getState();
if(count%2===1){
store.dispatch({
type:'add',data:selectValue});
}
}
render() {
return (
<div>
<h1>count:{
store.getState()}</h1>
<select onChange={
(e)=>this.setState({
selectValue:e.target.value})}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={
this.add}>+</button>
<button onClick={
this.sub}>-</button>
<button onClick={
this.asyncAdd}>异步加</button>
<button onClick={
this.oddAdd}>奇数加</button>
</div>
);
}
}
import React from 'react';
import ReactDOM from 'react-dom'
import App from "./App";
import store from './redux/store';
ReactDOM.render(<App />,document.getElementById('root'));
store.subscribe(()=>{
ReactDOM.render(<App />,document.getElementById('root'));
})
精简版结束,里面没有涉及到actions因为action仅仅只是一个obj的对象。我们可以直接写一个对象替代,在后面的例子中我们会加入actions文件
和上一版的区别是增加了actions.js为我们生成action方法,在app.js发布方法不需要写对象了。直接调用actions.js里面的方法即可,为了防止因为马虎写错单词,我们可以新建一个constant.js文件来声明常量
export const ADD = 'add'
export const SUB = 'sub'
import {
ADD,SUB } from './constant';
export const add = (data) =>({
type: ADD,data});
export const sub = (data) =>({
type:SUB,data})
import {
ADD,SUB } from './constant';
export const countReducers = (preState=0,action) =>{
switch(action.type){
case ADD :
return preState + action.data*1;
case SUB :
return preState - action.data*1;
default :
return preState
}
}
import {
add,sub } from './redux/countActions';
//加
add = () =>{
const {
selectValue} = this.state;
store.dispatch(add(selectValue));
}
//减
sub = () =>{
const {
selectValue} = this.state;
store.dispatch(sub(selectValue));
}
//异步加
asyncAdd = () =>{
const {
selectValue} = this.state;
setTimeout(() => {
store.dispatch(add(selectValue));
}, 1000);
}
//奇数加
oddAdd = () =>{
const {
selectValue} = this.state;
const count = store.getState();
if(count%2===1){
store.dispatch(add(selectValue));
}
}
上面的例子有一个异步加的方法,他其实就是一个异步方法。异步action不是必须要使用的,可以把异步方法写到组件内。这样就不需要使用异步action了。就向上面的例子一样。
这个例子与异步action的区别就好比去饭店买了一份蛋炒饭,你可以等待5分钟再通知服务员点餐。这可以告诉服务员一份蛋炒饭5分钟之后上菜。这两种方法都可以实现5分钟之后来一份蛋炒饭这个目的,只是实现的方式不同,所以异步的action不是必须使用的。
同步action返回的是一个对象,异步action返回的是一个函数。
怎么使用异步action呢
redux不支持异步action,因此我们需要下载一个插件redux-thunk。可以用它通知store当接收到一个异步action返回的函数时,执行一下这个函数。
import {
createStore,applyMiddleware} from 'redux';
import {
countReducers} from './countReducers'
import thunk from 'redux-thunk';
export default createStore(countReducers,applyMiddleware(thunk));
import {
ADD,SUB } from './constant';
export const add = (data) =>({
type: ADD,data});
export const sub = (data) =>({
type:SUB,data});
export const asyncAdd = (data) =>{
return (dispatch) =>{
setTimeout(() => {
dispatch(add(data)) //store.dispathch(add(data))
}, 1000);
}
}
//异步加
asyncAdd = () =>{
const {
selectValue} = this.state;
store.dispatch(asyncAdd(selectValue));
}
异步action完成
import React, {
Component } from 'react';
import Count from './Container/Count'
import store from './redux/store'
export default class App extends Component {
render() {
return (
<div>
<Count store={
store}></Count>
</div>
);
}
}
import React, {
Component } from 'react';
class CountUI extends Component {
state={
selectValue : 1
}
//加
add = () =>{
const {
selectValue} = this.state;
this.props.add(selectValue)
}
//减
sub = () =>{
const {
selectValue} = this.state;
this.props.sub(selectValue)
}
//异步加
asyncAdd = () =>{
const {
selectValue} = this.state;
this.props.asyncAdd(selectValue)
}
//奇数加
oddAdd = () =>{
const {
selectValue} = this.state;
if(this.props.count % 2 ===1){
this.props.add(selectValue)
}
}
render() {
return (
<div>
<h1>count:{
this.props.count}</h1>
<select onChange={
(e)=>this.setState({
selectValue:e.target.value})}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={
this.add}>+</button>
<button onClick={
this.sub}>-</button>
<button onClick={
this.asyncAdd}>异步加</button>
<button onClick={
this.oddAdd}>奇数加</button>
</div>
);
}
}
export default CountUI;
import {
connect } from 'react-redux';
import CountUI from '../Components/CountUI'
import {
add,asyncAdd,sub} from '../redux/countActions'
const mapStateToProps = (state) =>{
return{
count: state
}
}
const mapDispatchToProps = (dispatch) =>{
return {
add : (data)=>dispatch(add(data)),
asyncAdd : (data)=>dispatch(asyncAdd(data)),
sub : (data)=>dispatch(sub(data)),
}
}
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)
import {
connect } from 'react-redux';
import CountUI from '../Components/CountUI'
import {
add,asyncAdd,sub} from '../redux/countActions'
// const mapStateToProps = (state) =>{
// return{
// count: state
// }
// }
// const mapDispatchToProps = (dispatch) =>{
// return {
// add : (data)=>dispatch(add(data)),
// asyncAdd : (data)=>dispatch(asyncAdd(data)),
// sub : (data)=>dispatch(sub(data)),
// }
// }
export default connect(
state=>({
count:state}),
{
add,
asyncAdd,
sub
}
)(CountUI)
import React from 'react';
import ReactDOM from 'react-dom'
import App from "./App";
ReactDOM.render(<App />,document.getElementById('root'));
// store.subscribe(()=>{
// ReactDOM.render( ,document.getElementById('root'));
// })
app.js
import React, {
Component } from 'react';
import Count from './Container/Count'
import store from './redux/store'
export default class App extends Component {
render() {
return (
<div>
<Countx></Count>
//
//
//
//
</div>
);
}
}
修改index.js
import React from 'react';
import ReactDOM from 'react-dom'
import App from "./App";
import store from './redux/store';
import {
Provider} from 'react-redux'
ReactDOM.render(
<Provider store={
store}>
<App />
</Provider>
,document.getElementById('root'));
import {
connect } from 'react-redux';
import React, {
Component } from 'react';
import {
add,asyncAdd,sub} from '../redux/countActions'
class CountUI extends Component {
state={
selectValue : 1
}
//加
add = () =>{
const {
selectValue} = this.state;
this.props.add(selectValue)
}
//减
sub = () =>{
const {
selectValue} = this.state;
this.props.sub(selectValue)
}
//异步加
asyncAdd = () =>{
const {
selectValue} = this.state;
this.props.asyncAdd(selectValue)
}
//奇数加
oddAdd = () =>{
const {
selectValue} = this.state;
if(this.props.count % 2 ===1){
this.props.add(selectValue)
}
}
render() {
return (
<div>
<h1>count:{
this.props.count}</h1>
<select onChange={
(e)=>this.setState({
selectValue:e.target.value})}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
</select>
<button onClick={
this.add}>+</button>
<button onClick={
this.sub}>-</button>
<button onClick={
this.asyncAdd}>异步加</button>
<button onClick={
this.oddAdd}>奇数加</button>
</div>
);
}
}
export default connect(
state=>({
count:state}),
{
add,
asyncAdd,
sub
}
)(CountUI)
新增一个组件person 和 count 共享状态
修改目录结构
redux文件夹下新建actions文件夹和reducers文件夹,把所有的action和reducer全部放入对应的文件夹中
person的action为
import {
ADD_PERSON } from "../constant";
export const addPerson = (obj) => ({
type: ADD_PERSON, data:obj})
person的reducer为
import {
ADD_PERSON
} from "../constant";
const initPerson = [{
name: '张三',
id: 1,
hobby: '篮球'
}]
export const person = (preState = initPerson, action) => {
const {
type,
data
} = action;
switch (type) {
case ADD_PERSON:
return [...preState, data]
default:
return preState
}
}
因为现在有person和count两个reducer所以给store就不能只是count的reducer了。这时候就要用combineReducers来把reducer联合一起
修改store.js
import {
createStore,applyMiddleware,combineReducers} from 'redux';
import {
count} from './reducers/count'
import {
person } from './reducers/person';
import thunk from 'redux-thunk';
export default createStore(combineReducers({
count,person}),applyMiddleware(thunk));
因为修改combineReducers就相当于修改了redux里面存储的结构。只有一个count组件时,redux里面仅仅是一个0。现在redux存储的是一个对象,{count:0,person:{…person内容}}
所以count.jsx的connect也应该修改
export default connect(
state=>({
count:state.count,person: state.person}),
{
add,
asyncAdd,
sub
}
)(CountUI)
person.jsx组件内容
import React, {
Component } from 'react';
import {
connect } from 'react-redux';
import {
addPerson } from '../redux/actions/person';
class Person extends Component {
state = {
}
add = () =>{
this.props.addPerson({
name:this.name.value,hobby:this.hobby.value,id:this.name.value})
}
render() {
return (
<div>
<input ref={
(name)=> this.name = name} type="text" />
<input ref={
(hobby)=> this.hobby = hobby} type="text" />
<button onClick={
this.add}>添加</button>
<h1>和为:{
this.props.count}</h1>
<ul>
{
this.props.person.map((p)=>{
return <li key={
p.id}>{
p.name}-----{
p.hobby}</li>
})
}
</ul>
</div>
);
}
}
export default connect(
state => ({
count: state.count, person: state.person }),
{
addPerson
})(Person);