这篇学习主要是围绕Redux
展开的..
宇宙惯例..github地址 ⭐⭐⭐
Redux
-
Redux
和React
没关系 redux也可以用在其他框架里 甚至是原生的js代码也可以用 -
Redux的工作流程
-
- 先上一图流(字丑莫介意..orz)
- 先做好各种初始化工作 例如安装好
Redux
, 组件中引入store
并定义好各个文件的配置store.getState()
和当前state
做绑定 在此不过多赘述了 -
//例如 // store.index.js中 (store) import { createStore } from 'redux' import reducer from './reducer' const store = createStore( reducer ) //reducer.js中 //默认值 const defaultState = { value: '' } export default = ( state = defaultState, action )=>{ return state } 复制代码
- 组件中定义一个action的对象
- 通常为了更便于维护和管理 我们将要用到的
action
对象拆分成一个单独的actionCreators.js
文件 里面是一个一个的返回一个对象的函数 返回的对象有以下属性- type: 用于之后检测的标识值
- 要传递更改的数据
//例如 //actionCreators.js中定义 export const getChangeAction = (value) => ({ type : 'change_value', value }) //组件中定义实际要用的action对象 import { getChangeAction } from './store/actionCreators' const action = getChangeAction('testValue) 复制代码
- 组件中将定义好的
action
对象通过store.dispatch()
方法将其派发出去
//例如 store.dispatch(action) 复制代码
reducer.js
- 在
reducer.js
函数中利用 之前定义好的action.type
对传递来的对象进行拦截
需要注意的是 在进行数据的更改时
reducer
里不能进行原始数据的更改 只能将数据进行一次深拷贝 将拷贝下来的数据更改 然后再返回给store
让它对数据进行更新- 在
//例如 export default = ( state = defaultState, action )=>{ if( action.tyle === 'change_value' ){ const newState = JSON.parse(JSON.stringify(state)) newState.value = action.value return newState } return state } 复制代码
- 到目前为止 数据以及更新完毕 但是视图层还没有更新 所以我们现在应该去更新视图层 需要在组件里 调用
store.subscribe()
这个方法用来监听store
里数据的变化同时接受一个函数作为参数, 如果store
发生变化就调用传进去的那个函数 所以我们可以这么写
//在constructor里 //不要忘记更改this指向 this.handleStoreChange = this.handleStoreChange.bind(this) store.subscribe(this.handleStoreChange) //handleStoreChange函数 handleStoreChange(){ this.setState(store.getState()) } 复制代码
大功告成
- 先上一图流(字丑莫介意..orz)
-
react-redux
react-redux
也是用来做数据管理的 只不过是利用了react本身的一些特性, 因为react是单向数据流 所以我们索性把store
集成到所有组件的顶层组件里, 即 顶层的props
里Provider
上做关联 连接 store 内部组件都可以获取store上的内容了
//入口文件中 (index.js) import { Provider } from 'react-redux' const App = ( <Provider store={store} > <TodoList/> </Provider> ) ReactDOM.render(App, document.getElementById('root')); 复制代码
- 子组件通过
connect
获取connect
的第二个括号就是组件本身 第一个口号里需要两个参数 这两个参数都是两个函数 两个映射关系
//组件中 //state 是 store里的数据 // 这个映射的规则就是 把 store里的数据映射到当前的props上 const mapStoreStateToProps = (storeState) => { return { inputValue : storeState.inputValue } } // store.dispatch 挂到 当前的props上 const mapStoreDispatchToProps = (storeDispatch) => { return { changeInputValue(e){ const action = { type : 'change_input_value', value: e.target.value } storeDispatch(action) } } } export default connect(mapStoreStateToProps , mapStoreDispatchToProps)(TodoList); 复制代码
-
Redux-thunk
中间件- 这个中间件使得我们可以在action里返回一个函数 使得一些异步操作 比如 获取ajax请求可以从组件中抽离出去
// 使用了 redux-thunk 后 action不仅仅只能是一个对象了 还可以是一个函数
export const getTodo = () =>{
// 返回的函数中的第一个参数就是dispatch方法
return (dispatch) =>{
$.get('something..').then(res=>{
console.log(res)
}).catch(()=>{
console.log('error');
})
}
}
复制代码
由于在 `action` 和 `store`之间是通过 `dispatch`这个方法来进行沟通的 , 所以`redux-thunk`这个中间件实际上就是对`dispatch`的一个封装, 或者一个升级, 最原始的`dispatch`只能返回一个对象 然后再把这个对象返回给`store`, 使用了 `redux-thunk`之后, 我们可以传给`dispatch`一个函数 , 他就会先自动执行一遍这个函数, 执行完了之后 再将处理后或者执行完函数后的结构返回给store<br/>
一图流, `midWare`就是中间件处理的位置
复制代码
- 还有很多其他中间件就不一一枚举了..
组件分类
- UI组件与容器组件 (傻瓜组件和聪明组件)
- UI组件只负责样式
- 例如 将demo用的 todolist拆分
const TodoListUI = (props) =>{
return (
<div style={{ margin: " 0 auto ", width: "400px", paddingTop: "150px" }}>
<div style={{ margin: "10px" }}>
<Input
placeholder="todo"
value={props.inputValue}
style={{ width: "300px", marginRight: "10px" }}
onChange={props.handleInputChange}
/>
<Button onClick={props.handleBtnClick} type="primary">提交</Button>
</div>
<List
style={{ margin: "10px", width: "300px" }}
bordered
dataSource={props.list}
header='todo'
renderItem={(item,index )=> <List.Item onClick={()=>{props.handleItemClick(index)}}>{item}</List.Item>}
/>
</div>
)
}
更多详情见 github.. todolist2.0里面的代码
复制代码
-
容器组件负责逻辑 功能实现 与UI组件之间通过
props
连接 -
无状态组件
- 只有render函数的组件
- 优势是性能比较高 因为它就是一个函数 不需要有相关的生命周期初始化过程