文件目录
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Todolist from './Todolist'
//以上都是固定格式
import {Provider} from 'react-redux'//被provider包裹的都可以获得store里面的值
import store from './store'
const App = (//提供器,包裹所有需要的组件
<Provider store={store}>
<Todolist />
</Provider>
)
ReactDOM.render(App, document.getElementById('root'))
// ReactDOM.render(<Todolist />, document.getElementById('root'))
react-redux还需要安装
注意修改render里面的值,之前事todolist主文件的闭合标签,现在是一个提供器。
Todolist.js
引入
import React, { Component } from 'react';
import store from './store/index'
import TodolistUI from './TodolistUI'
import {changeInputAction,addItemAction,deleteItemAction,getMyListAction} from './store/actionCreators'
import {connect} from 'react-redux'
TodolistUI是将页面组件部分拆分出了的一个文件。
actionCreators是一个action的定义空间。
connect是redux的一个组件。
class代码
class Todolist extends Component {
// //console.log(store.getState())//获取仓库里面的值
// // store.subscribe(this.storeChange)//subscribe监听store中每次修改情况
//
render() {
return (
<TodolistUI
inputValue={this.props.inputValue}
changeInputeValue={this.props.changeInputValue}
clickbtn = {this.props.clickBtn}
list = {this.props.list}
deleteItem={this.props.deleteItem}
/>
);
}
componentDidMount(){//axios需要在声明周期函数内进行
// const action = getTodoList()
// store.dispatch(action)
const action = getMyListAction()
store.dispatch(action)
console.log(action)
}
storeChange(){
this.setState(store.getState())
}
}
由于connect具有监听store的功能,subscribe监听就没有用了
TodoListUI为展示组件,由于使用了connect,this.state变成了this.props。
axios异步交互需要放在生命周期函数内执行。
componentDidMount的执行期是在render后面执行,是在组件已经完全挂载到网页上才会调用被执行,所以可以保证数据的加载。
connect的两个组件
const stateToProps =(state)=>{
return {
inputValue:state.inputValue,
list:state.list
}
}
const dispatchToProps = (dispatch)=>{
return{
changeInputValue(e) {
let action = changeInputAction(e.target.value)
dispatch(action)
},
clickBtn(){
let action = addItemAction()
dispatch(action)
},
deleteItem(index){
const action = deleteItemAction(index)
dispatch(action)
}
}
}
export default connect(stateToProps,dispatchToProps)(Todolist);//两个参数都表示映射关系
第一个参数负责将通过state获得的数据映射到展示组件的this.props
第二个参数负责将用户操作转化为Action的功能函数映射到展示组件的this.props
第一个参数具有监听store的功能。
TodolistUI
引入
import React from 'react';//不需要component的函数就不用写{ Component }
import 'antd/dist/antd.css'
import {Input,Button ,List} from 'antd'
UI组件主要是一些页面展示
该组件采用了ant design的模板。引入了input,list和button
//无状态组件没有state,性能更强一些。
const TodolistUI=(props)=>{
return (
<div style={{margin:'10px'}}>
<div>
<Input
placeholder = {props.inputValue}
style={{width:'250px',marginRight:'10px'}}
onChange={props.changeInputeValue}
/>
<Button
type="primary" //antd 里的Primary按钮
onClick={props.clickbtn}
>
增加
</Button>
</div>
<div style={{margin:'10px',width:'300px'}}>
<List
bordered//边框
dataSource = {props.list}//变量都是固定格式。
renderItem={(item,index)=>(<List.Item onClick={()=>{props.deleteItem(index)}}>{item}</List.Item>)}//List.item 是List的一个固定标签
//不声明,函数内用item,
>
</List>
</div>
</div>
);
}
export default TodolistUI;
除render外,没有其他函数,所以采用无状态组件。
无状态组件
无状态组件不存在state,只会有props,也就没有生命周期函数,所以性能比有状态组件强。
由Todolist可知,Todolist向UI组件内传入值,props接收值。
Store文件夹
index.js
Saga
import {createStore , applyMiddleware , compose} from 'redux'
import Reducer from './reducer'
//import thunk from 'redux-thunk'
import creatSagaMiddleware from 'redux-saga'
import mySagas from './sagas'
const sagaMiddleware = creatSagaMiddleware()
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}):compose
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))//thunk
const store = createStore(Reducer,enhancer)//creatStore只能传两个参数,所以利用compose增强函数
sagaMiddleware.run(mySagas)//saga专属
export default store
采用的是saga进行异步加载,引入creatSagaMiddleware用于创造中间件。
saga需要额外建立一个文件进行操作。
composeEnhancers主要是用来检测有没有用reduxtools,(用于检查redux的插件。)
applyMiddleware redux自带的函数,返回store对象,
sagaMiddleware.run(mySagas) saga需要运行另一个执行文件
sagas.js
import { takeEvery,put } from 'redux-saga/effects'//默认格式
import { GET_MY_LIST } from './actionTypes'
import {getListAction} from './actionCreators'
import axios from 'axios'
function* mySaga(){
yield takeEvery(GET_MY_LIST,getList)//等待监听
}
function* getList(){
const res = yield axios.get('https://mock.yonyoucloud.com/mock/17500/demo1/xiaojiejie')
const action = getListAction(res.data)
yield put(action)
}
//generator
export default mySaga
yield takeEvery(GET_MY_LIST,getList) GET_MY_LIST是在页面组件加载完成之后才进行的。(getMyListAction就是GET_MY_LIST),在componentDidMount里面执行,也就是在页面组件加载完成之后进行的。
GET_MY_LIST作用后,getlist开始作用了。获取接口,然后用 put 将action传入reducer,然后getListAction 获取list列表并返回给UI组件。
reducer.js
import {CHANGE_INPUT,ADD_ITEM,DELTE_ITEM, GET_LIST} from './actionTypes'
const defaultState = {
inputValue:'Write Something',
list:[]
}
export default (state = defaultState,action)=>{
//Reducer里只能接收state,不能改变state。
if(action.type===CHANGE_INPUT){
let newState = JSON.parse(JSON.stringify(state))//创建一个局部变量,修改局部变量来代替修改state
newState.inputValue = action.value//action为传递过来的值 dispatch
return newState //newState的inputValue已经是新输入了的
}
if(action.type===ADD_ITEM){
let newState = JSON.parse(JSON.stringify(state))
newState.list.push(newState.inputValue)
newState.inputValue=''
return newState
}
if(action.type===DELTE_ITEM){
let newState = JSON.parse(JSON.stringify(state))
newState.list.splice(action.index,1)
return newState
}
if(action.type===GET_LIST){
let newState = JSON.parse(JSON.stringify(state))
newState.list = action.data.data//action 为传入的值,action.data表示的是action里面的数据,action.data.data才是接口里面的属性
return newState
}
return state
}
引入的都是一些命名格式。
let newState = JSON.parse(JSON.stringify(state)) 相当于深度克隆。
actionTypes.js
export const CHANGE_INPUT ='changeInpute'//全大写的是常量
export const ADD_ITEM= 'addItem'
export const DELTE_ITEM = 'deleteItem'
export const GET_LIST = 'getList'
export const GET_MY_LIST='getMyList'
将action的type命名规范化。
actionCreators.js
import {CHANGE_INPUT, GET_MY_LIST} from './actionTypes'
import {ADD_ITEM} from './actionTypes'
import {DELTE_ITEM} from './actionTypes'
import {GET_LIST} from './actionTypes'
export const changeInputAction = (value)=>({
type:CHANGE_INPUT,
value
})
export const addItemAction = ()=>({
type:ADD_ITEM
})
export const deleteItemAction = (index)=>({
type:DELTE_ITEM,
index
})
export const getListAction = (data)=>({
type:GET_LIST,
data
})
export const getMyListAction = (data) =>({
type:GET_MY_LIST
})