redux是一个用来管理状态(数据)的框架。
例如,一个组建的数据共享到其他组建,A1-1组建的数据要在A2和A2-1中使用,用以往的方式通过组建间传递也能实现,但是太过麻烦,如果项目较大,数据交互较多的场景,数据维护更为复杂,所以更适合将公共的数据放到公共的仓库中。
事实上,大多数情况,你可以不用它,只用 React 就够了。
曾经有人说过这样一句话。
“如果你不知道是否需要 Redux,那就是不需要它。”
Redux 的创造者 Dan Abramov 又补充了一句。
“只有遇到 React 实在解决不了的问题,你才需要 Redux 。”
简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
- 用户的使用方式非常简单
- 用户之间没有协作
- 不需要与服务器大量交互,也没有使用 WebSocket
- 视图层(View)只从单一来源获取数据
上面这些情况,都不需要使用 Redux。
我不做大型项目,那么我还要去学习吗?
当然要学,现在不做大型项目,不代表以后不做大型项目,要为未来铺路,面试关于react技术栈,几乎必问redux,所以也为面试增砖添瓦。
利用create-react-app快速初始化项目
create-react-app redux-demo
清理项目结构
安装redux
npm i redux
在src下创建store文件夹,在store下创建index.js
创建redux仓库
import {
createStore } from 'redux'
const defaultState = {
count: 1
}
const store = createStore((state = defaultState) => {
return state
})
export default store
通过getState获取仓库的数据并展示
import React from 'react';
import store from './store'
export default class App extends React.Component {
constructor (props) {
super(props)
this.state = store.getState()
}
render () {
return (
<div>
{
this.state.count }
</div>
)
}
}
创建reducer.js文件
// 仓库数据
const defaultState = {
count: 1
}
const reducer = (state = defaultState) => {
return state
}
export default reducer
在store/index.js中引入
import {
createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
准备Add组建
import React from 'react';
import store from './store'
export default class Add extends React.Component {
constructor (props) {
super(props)
this.state = store.getState()
}
render () {
return (
{ this.state.count }
)
}
}
准备sub组建
import React from 'react';
import store from './store'
export default class Sub extends React.Component {
constructor (props) {
super(props)
this.state = store.getState()
}
render () {
return (
{ this.state.count }
)
}
}
在App中使用
import React from 'react';
import Add from './Add'
import Sub from './Sub'
export default class App extends React.Component {
render () {
return (
<div>
<Add />
<p>-----------</p>
<Sub />
</div>
)
}
}
这样只修改了当前组建state,并不是修改了redux的store仓库的数据
addCount = () => {
this.setState({
count: this.state.count + 1
})
}
render () {
return (
<div>
{
this.state.count }
<button onClick={
this.addCount }>+1</button>
</div>
)
}
add组建注册点击事件
render () {
return (
{ this.state.count }
)
}
通过dispatch触发修改state的操作,进行数据修改,参数是action
addCount = () => {
store.dispatch({
type: 'addCount'
})
}
在reducer纯函数中的第二个参数为action,action可以获取到dispatch操作的类型和数据
const reducer = (state = defaultState, action) => {
// reducer 不允许直接修改 state的数据
if (action.type === 'addCount') {
const newState = {
...state,
count: state.count + 1
}
return newState
}
return state
}
极简插件下载安装
配置
const store = createStore(
reducer, /* preloadedState, */
+ window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
通过store.subscribe的回调监听数据发生变化
componentDidMount () {
store.subscribe(this.storeChange)
}
storeChange = () => {
this.setState({
...store.getState()
})
}
给sub组建同样添加
传递数据
addCount = () => {
store.dispatch({
type: 'addCount',
value: 2
})
}
接收数据
// 仓库数据
const defaultState = {
count: 1
}
const reducer = (state = defaultState, action) => {
// reducer 不允许直接修改 state的数据
if (action.type === 'addCount') {
const newState = {
...state,
count: state.count + action.value
}
return newState
}
return state
}
export default reducer
注册事件
subCount = () => {
store.dispatch({
type: 'subCount',
value: 2
})
}
render () {
return (
{ this.state.count }
)
}
reducer中通过action处理
const reducer = (state = defaultState, action) => {
// reducer 不允许直接修改 state的数据
if (action.type === 'addCount') {
const newState = {
...state,
count: state.count + action.value
}
return newState
}
if (action.type === 'subCount') {
const newState = {
...state,
count: state.count - action.value
}
return newState
}
return state
}
因为在修改数据的时候,要通过store.dispath创建的type类型的值,和action中约定的值,从而实现数据修改,但是如果store.dispath创建的type类型的值或者action中约定的值写错,此时并不会报错,功能也不会实现,进而对调试有了难度。
创建actionType
const ADD_COUNT = 'ADD_COUNT'
const SUB_COUNT = 'SUB_COUNT'
export {
ADD_COUNT,
SUB_COUNT
}
修改reducer.js
import {
ADD_COUNT, SUB_COUNT } from './actionType'
// 仓库数据
const defaultState = {
count: 1
}
const reducer = (state = defaultState, action) => {
// reducer 不允许直接修改 state的数据
if (action.type === ADD_COUNT) {
const newState = {
...state,
count: state.count + action.value
}
return newState
}
if (action.type === SUB_COUNT) {
const newState = {
...state,
count: state.count - action.value
}
return newState
}
return state
}
export default reducer
修改Add组建
import React from 'react';
import store from './store'
import { ADD_COUNT } from './store/actionType'
export default class Add extends React.Component {
constructor (props) {
super(props)
this.state = store.getState()
}
componentDidMount () {
store.subscribe(this.storeChange)
}
storeChange = (e) => {
console.log(123)
this.setState({
...store.getState()
})
}
addCount = () => {
store.dispatch({
type: ADD_COUNT,
value: 2
})
}
render () {
return (
{ this.state.count }
)
}
}
修改Sub组建
import React from 'react';
import store from './store'
import { SUB_COUNT } from './store/actionType'
export default class Sub extends React.Component {
constructor (props) {
super(props)
this.state = store.getState()
}
componentDidMount () {
store.subscribe(this.storeChange)
}
storeChange = () => {
this.setState({
...store.getState()
})
}
subCount = () => {
store.dispatch({
type: SUB_COUNT,
value: 2
})
}
render () {
return (
{ this.state.count }
)
}
}
安装axios
yarn add axios
在Add组建中引入axios获取数据
import axios from 'axios'
componentDidMount () {
store.subscribe(this.storeChange)
this.loadNewsList()
}
async loadNewsList () {
const { data: res } = await axios.get('http://115.159.87.220:4000/books')
console.log(res)
}
定义type类型
const ADD_COUNT = 'ADD_COUNT'
const SUB_COUNT = 'SUB_COUNT'
const GET_NEWS = 'GET_NEWS'
export {
ADD_COUNT,
SUB_COUNT,
GET_NEWS
}
引入GET_NEWS并通过dispatch触发action
import {
ADD_COUNT, GET_NEWS } from './store/actionType'
async loadNewsList () {
const {
data: res } = await axios.get('http://115.159.87.220:4000/books')
console.log(res)
store.dispatch({
type: GET_NEWS,
value: res
})
}
在reducer中修改数据
import {
ADD_COUNT, SUB_COUNT, GET_NEWS } from './actionType'
// 仓库数据
const defaultState = {
count: 1,
news: []
}
const reducer = (state = defaultState, action) => {
// reducer 不允许直接修改 state的数据
if (action.type === ADD_COUNT) {
const newState = {
...state,
count: state.count + action.value
}
return newState
}
if (action.type === SUB_COUNT) {
const newState = {
...state,
count: state.count - action.value
}
return newState
}
if (action.type === GET_NEWS) {
const newState = {
...state,
news: action.value
}
return newState
}
return state
}
export default reducer