如何在react中使用redux

如何在react中使用redux

首先我们需要先要知道redux是什么,如何使用的,推荐大家可以看软一峰的教程,在redux中核心的就是ReducerActionstore 这里就不过多赘述了。


但是前提是理解概念,一下是个人的通俗理解:

Reducer:对数据进行一些响应操作的

Action: 是一个给reducer一个type和和一data,让reducer跟据type对store中的数据进行跟新

store: 是存储数据的地方

下面是在react中使用的过程,

前提

我们需要准备一个react的环境,就不多说了哈,我用的是Vite感觉挺快的使用起来。

然后需要安装redux

yarn add resux

接着需要一个文件夹来存放redux的代码,我命令为store,(我先描述下面是代码)会有个入口文件为index.ts这里是在其他地方需要引用的然后会有一个reducers文件加我们的store不可能只存放一个数据在一个工程中,接着是一个actions文件夹,这里是对应着reducers文件中的一些操作动作的文件夹。应为在actions的时候需要指定一个type,(传说这样写会有可能导致书写错无导致的bug,所以我们要把这些type储存起来,直接导入使用,减少手误),一个constant.ts

// 文件解构
store-----
----------actions
----------reducers
----------constant.ts
----------index.ts

需求

假设我们有一个list是存放人的,会有添加操作,添加的时候会有头插和尾插的区分(这个就是类型), 人有姓名年龄和id

需求明确那就开始写代码了

我们知道有两种操作头插和尾插先定义constant.ts

constant.ts

export const PUSH_ADD_PERSON = 'push_add_person'
export const UNSHIFT_ADD_PERSON = 'unshift_add_person'

接着创建list的reducer,在reducers文件夹下创建personList.ts

store/reducers/personList.ts

import { UNSHIFT_ADD_PERSON,PUSH_ADD_PERSON } from './../constant'
// 创建一个人的类型
type Person = {
  age:number;
  name: string,
  id: number
}
// 初始化store中的数据 
// 假设初始化的时候一个人
const initState:Array<Person> = [
  { id: 1, name: '女娲',age:1000 }
]
export default (preState:Array<Person> = initState, action:{type:string,data:Person}) => {
  const { type,data } = action
  // 依据不同的类型做不同的操作
  switch(type){
    case UNSHIFT_ADD_PERSON:
      return [data,...preState];
    case PUSH_ADD_PERSON:
      return [...preState,data];
    default: return preState
  }
}

接着就是写action了,(个人理解,这里就是指定一个action传给reducer执行操作的)定义一个personList对应的操作

store/actions/personList.ts

import { PUSH_ADD_PERSON, UNSHIFT_ADD_PERSON } from './../constant';
type Person = {
  age:number;
  name: string,
  id: number
}
export const pushAddPerson = (data:Person) => ({ type:PUSH_ADD_PERSON, data })
export const unshiftAddPerson = (data:Person) => ({ type:UNSHIFT_ADD_PERSON, data })

接着历史入口文件index

store/index.ts

import { createStore, combineReducers } from 'redux'
/*
createStore: 依据reducer创建出来的一个store
combineReducers: 我们有多个reducer,但是createStore只接受一个参数,需要经过combineReducers处理为一个对象的store
*/
// 引入reducers文件夹的reducer
import personList from './reducers/personList'

// 通过combineReducers合并reducers
const allReducer = combineReducers({ personList })
// 创建store
const store = createStore(allReducer, )
export default store

引入方法一

我们的第一种方法就是直接引用不借助其他的依赖

我们用脚手架创建的main.ts里的东西是这样的

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>,
  document.getElementById('root')
)

我们重新下一个测试的页面出来Person.tsx,也可以直接在App.tsx中写

App.tsx or Person.tsx

这里我们就是有两个输入框姓名和年龄,和两个按钮头插和尾插

import React, { ChangeEvent,Component } from 'react'


type stateType = {
  age:number;
  name:string
}

class App extends Component {
  state:stateType = {
    age: 0,
    name: ''
  }
  unshiftClick = () => {
    // 头插操作
  }
  pushClick = () => {
    // 尾插操作
  }
  render () {
    return(
      <>
        <div>
          姓名:<input onChange={((event:ChangeEvent<HTMLInputElement>)=>{ this.setState({name: event.target.value}) })} type='text'/>
          年龄:<input onChange={((event:ChangeEvent<HTMLInputElement>)=>{ this.setState({age: +event.target.value}) })}  type='number'/>
          <button onClick={this.unshiftClick}>头插</button>
          <button onClick={this.pushClick}>尾插</button>
        </div>
      </>
    )
  }

}
export default App

现在我们直接把store引入,然后打印看效果

这里可知getStore可以获取store中的数据

我们拿到了数据是去渲染出来

说明我我们可以得到数据也可以展示,接下来就是操作数据的跟新了

我们知道redux是异步跟新数据的,需要触发事件跟新和鉴定 也就是发布订阅 dispatchsubscribe

看代码

import React, { ChangeEvent,Component } from 'react'

// 引入store
import store from './redux'

// 引入事件
import { pushAddPerson,unshiftAddPerson } from './redux/actions/personList'
type stateType = {
  age:number;
  name:string;
  personList:Array<Person>
}
type Person = {
  age:number;
  name: string,
  id: number
}
class App extends Component {
  state:stateType = {
    age: 0,
    name: '',
    personList:[]
  }
  componentDidMount(){
    // 拿到数据放在state中 这样做为了让state中的数据变化更新页面
    const { personList } = store.getState()
    this.setState({personList})
    // 在组件挂在后订阅
    store.subscribe(()=>{
      const { personList } = store.getState()
      this.setState({personList})
    })
  }
  unshiftClick = () => {
    // 头插操作
    store.dispatch(unshiftAddPerson({ id: this.state.personList.length + 1, name:this.state.name, age:this.state.age }))
  }
  pushClick = () => {
    // 尾插操作
    store.dispatch(pushAddPerson({ id:this.state.personList.length + 1, name:this.state.name, age:this.state.age }))
  }
  render () {
    const { personList } = store.getState()
    return(
      <>
        <div>
          姓名:<input onChange={((event:ChangeEvent<HTMLInputElement>)=>{ this.setState({name: event.target.value}) })} type='text'/>
          年龄:<input onChange={((event:ChangeEvent<HTMLInputElement>)=>{ this.setState({age: +event.target.value}) })}  type='number'/>
          <button onClick={this.unshiftClick}>头插</button>
          <button onClick={this.pushClick}>尾插</button>
        </div>
        <div>
          <h2>展示personList的数据</h2>
          <ul>
            {
              personList.map(item =>(
                <li key={item.id}>{item.name || '--'},年龄{item.age}</li>
              ))
            }
          </ul>
        </div>
      </>
    )
  }

}
export default App

页面正常,重点是我们拿到了store中的数据,放在state中,在页面刚挂在的时候进行订阅store,把变化的值放在store中页面页面刷新展示数据

如果过我们没有用过react的化这样写是没问题的,在没有框架的时候用到stare,不是把数据放在sessionStorage就是用这中,写一大堆的发布订阅来完成状态的同步的。现在react中我们也可以自己封装一下。这个可以自己提升,后面为大家,分装一个redux,接下来看下react-redux是如何用的

引入方法二(react-redux)

在react中状态是在全局的肯定是在跟组件对的,我们不可能一层一层的通过props传递的,这样写也不规范的

我们直接就看代码实现react-redux

根据提示我们要把App.tsx进行改造

    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './App'
+   import store from './redux'
+   import { Provider } from 'react-redux'
    ReactDOM.render(
      <React.StrictMode>
-       <App/>
+    	<Provider store={store}><App /></Provider>
      </React.StrictMode>,
      document.getElementById('root')
    )

可以看到使用react-resux提供的Provider包裹了一层,并把store传递给了它 ,被Provider包裹的组件就可以通过特殊的方式(也是react-redux提供的)获取到store了

接着看App.tsx如何才能拿到数据

import React, { ChangeEvent,Component } from 'react'
import { connect } from 'react-redux'

// 引入事件
import { pushAddPerson,unshiftAddPerson } from './redux/actions/personList'
type stateType = {
  age:number;
  name:string;
}
type Person = {
  age:number;
  name: string,
  id: number
}
type Props = {
  personList: Array<Person>;
  pushAddPerson: Function,
  unshiftAddPerson: Function
}
class App extends Component<Props> {
  state:stateType = {
    age: 0,
    name: '',
  }
  unshiftClick = () => {
    // 头插操作
    this.props.unshiftAddPerson({ id: this.props.personList.length + 1, name:this.state.name, age:this.state.age })
  }
  pushClick = () => {
    // 尾插操作
    this.props.pushAddPerson({ id:this.props.personList.length + 1, name:this.state.name, age:this.state.age })
  }
  render () {
    const { personList } = this.props
    return(
      <>
        <div>
          姓名:<input onChange={((event:ChangeEvent<HTMLInputElement>)=>{ this.setState({name: event.target.value}) })} type='text'/>
          年龄:<input onChange={((event:ChangeEvent<HTMLInputElement>)=>{ this.setState({age: +event.target.value}) })}  type='number'/>
          <button onClick={this.unshiftClick}>头插</button>
          <button onClick={this.pushClick}>尾插</button>
        </div>
        <div>
          <h2>展示personList的数据</h2>
          <ul>
            {
              personList.map(item =>(
                <li key={item.id}>{item.name || '--'},年龄{item.age}</li>
              ))
            }
          </ul>
        </div>
      </>
    )
  }
}
export default connect(
  (state:any) => ({personList: state.personList}),
  { pushAddPerson,unshiftAddPerson }
)(App)

在这里是用到了connect这个东西,应该叫高阶组件HOC,connect接受了两个参数,一个处理store的函数和一个action的 对象集合

内部原理应该是connect这个函数里,根据第一个参数fn获取到了personList里的数据了,然后开启可能开启了监听,并返回一个fn(注意这里的拿到的personList和action的 对象集合,进行合并,然后生成了一个新的函数这个新函数中引用到了拿到的数据也就是闭包)然后执行App

下面是伪代码

connect(getStoreFn,someAction){
    // 获取store 这里是可以拿到的,别忘记根组件是被react-redux的Provider包裹的
    const store = xxxxxx
    //todo 获取数据 这里是根据用户的参数决定的我之前在getStoreFn这个函数中写了返回personList就只有personList了,可以写store中有的任何数据
    const propsStore = getStoreFn(store)
    
    // 做一些数据的监听吧,有数据变化了就传递给 component
    // someAction 把someAction中的数据操作进行处理和对应展开
    ...
    pushAddPerson = () => {}
    unshiftAddPerson = () => {}
    return (component)=>{
        component.rorps ={
            propsStore,
            pushAddPerson,
            unshiftAddPerson,
            component.rorps
        }
        //todo 一些操作
        return component // 从这里传递出去的就props了 在reactzhon 
	}
}
posted @ 2021-04-09 01:21  GQiangQ  阅读(259)  评论(0编辑  收藏  举报