我是靠谱客的博主 大方板栗,最近开发中收集的这篇文章主要介绍Redux入门,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.Redux概念简述

redux设计理念

  • Redux设计理念如上图,Redux要求把数据放到公共存储区域Store里,组件中尽量少放数据。当蓝色组件修改公共数据时,Store中的值发生改变,其他使用到该数据的组件到Store中取修改后的值即可。

  • Redux = Reducer+Flux

    Flux原本是官方提供的辅助React的数据层框架,但公共数据存储区域由于有很多Store而出现问题,故最终升级成Redux。

2.Redux工作流程

redux工作流程
* ReactComponents:每个组件(理解:借书的人)
* Store:存储数据的公共区域(理解:图书管理员)
* Action Creators:组件想获取的数据(理解:说的要借的书的话)
* Reducers:Store查询的内容(理解:管理员查看书的记录本)
* 用于理解的工作流程:可以看做是你到图书馆借书,你是借书的人[React Components],你说了一句你想借什么书[Action Creators]告诉图书管理员[Store],图书管理员查看他的记录本[Reducers],并返回给你你要的书。

3.使用Ant Design(React的UI框架)实现ToList页面布局

  • 安装Ant Design:yarn add antdnpm install antd --save

  • 使用Ant Design组件实例:

    //Todolist.js
    import React ,{Component} from 'react';
    import 'antd/dist/antd.css';//antd是全局变量
    import {Input,Button,List} from 'antd';
    const Names = [
    'Jack',
    'Sam',
    'Tom',
    'Daming'
    ]
    class Todolist extends Component{
    render(){
    return(
    <div style={{marginTop:'10px',marginLeft:"10px"}}>
    <div>
    {/*输入框组件*/}
    <Input placeholder="todoInfo" style={{width:'300px',marginRight:'10px'}}/>
    {/*按钮组件*/}
    <Button type="primary">提交</Button>
    {/*列表组件
    header列表头
    footer列表底
    bordered列表有边框
    dataSource列表渲染的数据资源
    renderItem怎么渲染,dataSource中的每一个数据都会调用renderItem中的函数进行渲染,将每一条数据渲染成List.Item的组件,数据的内容就是dataSource中每一项数据的内容
    */}
    <List
    
    header={<div>header</div>}
    footer={<div>footer</div>}
    bordered
    dataSource={Names}
    renderItem={item=>(<List.Item>{item}</List.Item>)}
    style={{marginTop:'10px',width:'300px'}}
    />
    </div>
    </div>
    )
    }
    }
    export default Todolist;
    • 使用时需要引入Ant Design的css样式【ant是全局变量】:import 'antd/dist/antd.css';
    • 使用对应组建时可以直接到Ant Design首页查看组件引入代码并使用:https://ant.design/docs/react/introduce-cn
    • 简单Input、Button、List组件的引用可参见上方代码,通过属性增改对应内容

4.创建Redux中的store

  • 安装redux:yarn add redux
  • (为了结构整齐,创建store文件夹,并新建index.js)在index.js中引入redux中的createStore方法,创建store的时候const store = createStore(reducer);需要将reducer(在store文件下创建reducer.js)传进来[可以理解为:创建管理员的时候要把小本子给他]。reducer(负责管理应用里的数据),返回的是一个函数,两个参数,第一个参数state是数据,action表示操作。使用时可以使用this.getState()获取store中的数据。
  • 完整代码:

    //【store/reducer.js】
    const defaultState = {
    //当前store中有inputValue和list两条数据
    inputValue:'123',
    list:[1,2]
    }
    //reducer是笔记本,笔记本中存放关于图书馆书籍的数据和对数据的操作内容,state即是整个图书馆里书籍的信息(Store中的数据)
    export default (state=defaultState,action)=>{
    return state;
    }
    //【store/index.js】
    import {createStore} from 'redux'
    import reducer from './reducer' //将笔记本引入进来
    //创建数据的公共存储仓库
    const store = createStore(reducer);
    export default store;
    //【Todolist.js】
    import React ,{Component} from 'react';
    import 'antd/dist/antd.css';//antd是全局变量
    import {Input,Button,List} from 'antd';
    import store from './store/index' //也可以直接写成 import store from './store' 会默认直接找index.js
    class Todolist extends Component{
    constructor(props) {
    super(props);
    //console.log(store.getState()); //store的方法,用于获取store中的数据
    this.state=store.getState();
    console.log(this.state);
    }
    render(){
    return(
    <div style={{marginTop:'10px',marginLeft:"10px"}}>
    <div>
    {/*输入框组件*/}
    <Input placeholder="todoInfo" style={{width:'300px',marginRight:'10px'}} value={this.state.inputValue}/>
    {/*按钮组件*/}
    <Button type="primary">提交</Button>
    {/*列表组件
    header列表头
    footer列表底
    bordered列表有边框
    dataSource列表渲染的数据资源
    renderItem怎么渲染,dataSource中的每一个数据都会调用renderItem中的函数进行渲染,将每一条数据渲染成List.Item的组件,数据的内容就是dataSource中每一项数据的内容
    */}
    <List
    
    header={<div>header</div>}
    footer={<div>footer</div>}
    bordered
    dataSource={this.state.list}
    renderItem={item=>(<List.Item>{item}</List.Item>)}
    style={{marginTop:'10px',width:'300px'}}
    />
    </div>
    </div>
    )
    }
    }
    export default Todolist;

5.Action和Reducer的编写

  • 在Chrome网上应用店安装Redux DevTools(Chrome浏览器插件,用于调试Redux)

  • 网页上使用开发者工具Redux调试需要在createStore第二个参数写上window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()。表示如果window有变量(Redux的开发者工具扩展)则执行对应方法(使用对应工具)。

  • 注意:reducer可以接收state,但是不能修改state(通常是将之前的state拷贝一份出来,改变拷贝的state,return改变后的state,return的数据返回给了store,store会拿新的数据替换老的数据,此时store中的数据就被替换了)。

  • 实例代码:

    //[store/reducer.js]
    const defaultState = {
    //当前store中有inputValue和list两条数据
    inputValue:'123',
    list:[1,2]
    }
    //reducer是笔记本,笔记本中存放关于图书馆书籍的数据和对数据的操作内容,state即是整个图书馆里书籍的信息(Store中的数据)
    //reducer可以接受state,但是不能修改state
    export default (state=defaultState,action)=>{
    console.log(state,action); //state表示上次的存储state,action表示用户传递过来的那句话
    if(action.type === 'change_input_value'){
    const newState = JSON.parse(JSON.stringify(state));//对之前的state做一个深拷贝
    newState.inputValue = action.value;
    return newState;
    }else if(action.type === 'add_todo_item'){
    const newState = JSON.parse(JSON.stringify(state));
    newState.list = [...newState.list,newState.inputValue];
    newState.inputValue='';
    return newState;
    }
    return state;
    }
    //[store/index.js]
    import {createStore} from 'redux'
    import reducer from './reducer' //将笔记本引入进来
    //创建数据的公共存储仓库
    const store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
    export default store;
    //[Todolist.js]
    import React ,{Component} from 'react';
    import 'antd/dist/antd.css';//antd是全局变量
    import {Input,Button,List} from 'antd';
    import store from './store/index' //也可以直接写成 import store from './store' 会默认直接找index.js
    class Todolist extends Component{
    constructor(props) {
    super(props);
    //console.log(store.getState()); //store的方法,用于获取store中的数据
    this.state=store.getState();
    console.log(this.state);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleStoreChange = this.handleStoreChange.bind(this);
    this.handleButtonClick = this.handleButtonClick.bind(this);
    store.subscribe(this.handleStoreChange);//将handleStoreChange函数订阅给store,每当store中的数据发生变化的时候将调用此函数
    }
    render(){
    return(
    <div style={{marginTop:'10px',marginLeft:"10px"}}>
    <div>
    {/*输入框组件*/}
    <Input placeholder="todoInfo" onChange={this.handleInputChange} style={{width:'300px',marginRight:'10px'}} value={this.state.inputValue}/>
    {/*按钮组件*/}
    <Button type="primary" onClick={this.handleButtonClick}>提交</Button>
    {/*列表组件
    header列表头
    footer列表底
    bordered列表有边框
    dataSource列表渲染的数据资源
    renderItem怎么渲染,dataSource中的每一个数据都会调用renderItem中的函数进行渲染,将每一条数据渲染成List.Item的组件,数据的内容就是dataSource中每一项数据的内容
    */}
    <List
    
    header={<div>header</div>}
    footer={<div>footer</div>}
    bordered
    dataSource={this.state.list}
    renderItem={item=>(<List.Item>{item}</List.Item>)}
    style={{marginTop:'10px',width:'300px'}}
    />
    </div>
    </div>
    )
    }
    handleInputChange(e){
    //创建action
    const action = {
    type:'change_input_value',//描述要做的事情
    value:e.target.value //表示改变inputvalue,变成e.target.value
    }
    store.dispatch(action); //将action传递给store
    }
    handleStoreChange(){
    this.setState(store.getState());//当store发生变化时,则调用此方法。用store中的数据替换当前组件的state数据。
    }
    handleButtonClick(){
    const action={
    type:'add_todo_item'
    }
    store.dispatch(action);
    }
    }
    export default Todolist;

6.使用Redux完成todolist的删除功能

  • 新增代码内容

    //[Todolist.js]
    import React ,{Component} from 'react';
    import 'antd/dist/antd.css';//antd是全局变量
    import {Input,Button,List} from 'antd';
    import store from './store/index' //也可以直接写成 import store from './store' 会默认直接找index.js
    class Todolist extends Component{
    constructor(props) {
    super(props);
    //console.log(store.getState()); //store的方法,用于获取store中的数据
    this.state=store.getState();
    console.log(this.state);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleStoreChange = this.handleStoreChange.bind(this);
    this.handleButtonClick = this.handleButtonClick.bind(this);
    store.subscribe(this.handleStoreChange);//将handleStoreChange函数订阅给store,每当store中的数据发生变化的时候将调用此函数
    }
    render(){
    return(
    <div style={{marginTop:'10px',marginLeft:"10px"}}>
    <div>
    {/*输入框组件*/}
    <Input placeholder="todoInfo" onChange={this.handleInputChange} style={{width:'300px',marginRight:'10px'}} value={this.state.inputValue}/>
    {/*按钮组件*/}
    <Button type="primary" onClick={this.handleButtonClick}>提交</Button>
    {/*列表组件
    header列表头
    footer列表底
    bordered列表有边框
    dataSource列表渲染的数据资源
    renderItem怎么渲染,dataSource中的每一个数据都会调用renderItem中的函数进行渲染,将每一条数据渲染成List.Item的组件,数据的内容就是dataSource中每一项数据的内容
    */}
    <List
    
    header={<div>header</div>}
    footer={<div>footer</div>}
    bordered
    dataSource={this.state.list}
    renderItem={(item,index)=>(<List.Item onClick={this.handleItemDelete.bind(this,index)}>{item}</List.Item>)}
    style={{marginTop:'10px',width:'300px'}}
    />
    </div>
    </div>
    )
    }
    handleInputChange(e){
    //创建action
    const action = {
    type:'change_input_value',//描述要做的事情
    value:e.target.value //表示改变inputvalue,变成e.target.value
    }
    store.dispatch(action); //将action传递给store
    }
    handleStoreChange(){
    this.setState(store.getState());//当store发生变化时,则调用此方法。用store中的数据替换当前组件的state数据。
    }
    handleButtonClick(){
    const action={
    type:'add_todo_item'
    }
    store.dispatch(action);
    }
    handleItemDelete(index){
    const action={
    type:'delete_todo_item',
    index:index
    }
    store.dispatch(action);
    }
    }
    export default Todolist;
    //[store/index.js]
    import {createStore} from 'redux'
    import reducer from './reducer' //将笔记本引入进来
    //创建数据的公共存储仓库
    const store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
    export default store;
    //[store/reducer.js]
    const defaultState = {
    //当前store中有inputValue和list两条数据
    inputValue:'',
    list:[]
    }
    //reducer是笔记本,笔记本中存放关于图书馆书籍的数据和对数据的操作内容,state即是整个图书馆里书籍的信息(Store中的数据)
    //reducer可以接受state,但是不能修改state
    export default (state=defaultState,action)=>{
    console.log(state,action); //state表示上次的存储state,action表示用户传递过来的那句话
    if(action.type === 'change_input_value'){
    const newState = JSON.parse(JSON.stringify(state));//对之前的state做一个深拷贝
    newState.inputValue = action.value;
    return newState;
    }else if(action.type === 'add_todo_item'){
    const newState = JSON.parse(JSON.stringify(state));
    newState.list = [...newState.list,newState.inputValue];
    newState.inputValue='';
    return newState;
    }else if(action.type === 'delete_todo_item'){
    const newState = JSON.parse(JSON.stringify(state));
    newState.list.splice(action.index,1);
    return newState;
    }
    return state;
    }
    • <List.item>绑定点击的监听事件handleItemDelete(),传递下标index
    • 在handleItemDelete方法中创建action,并利用store的dispatch方法将action传递给store
    • store将直接到reducer中查询,在reducer中添加匹配的type值判断并给出根据下标的splice方法返回新的state给store
    • store将新的state返回给TodoList组件
    • 由于Todolist组件利用store.subscribe()方法订阅了store,故会调用对应的handleStoreChange()方法,并在方法中利用store.getState()重新获取state值完成当前组件的state更新,进而重新渲染页面

7.ActionTypes的拆分

  • 有时我们会将定义的action的type值与reducer中判断的type值写错,从而导致项目运行不起来,但却没有报错,故我们可以将type值提取出来成一个新的文件。

  • 示例代码:[下述代码将只针对源码中的修改进行介绍]

    //[store/actionTypes.js]
    export const CHANGE_INPUT_VALUE = 'change_input_value';
    export const ADD_TODO_ITEM = 'add_todo_item';
    export const DELETE_TODO_ITEM = 'delete_todo_item';
    //[Todolist.js]
    //导入actionTypes.js文件
    import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from './store/actionTypes';
    //使用常量值
    handleInputChange(e){
    //创建action
    const action = {
    type:CHANGE_INPUT_VALUE,//描述要做的事情
    value:e.target.value //表示改变inputvalue,变成e.target.value
    }
    store.dispatch(action); //将action传递给store
    }
    handleButtonClick(){
    const action={
    type:ADD_TODO_ITEM,
    }
    store.dispatch(action);
    }
    handleItemDelete(index){
    const action={
    type:DELETE_TODO_ITEM,
    index:index
    }
    store.dispatch(action);
    }
    //[store/reducer.js]
    import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from './actionTypes';
    const defaultState = {
    //当前store中有inputValue和list两条数据
    inputValue:'',
    list:[]
    }
    //reducer是笔记本,笔记本中存放关于图书馆书籍的数据和对数据的操作内容,state即是整个图书馆里书籍的信息(Store中的数据)
    //reducer可以接受state,但是不能修改state
    export default (state=defaultState,action)=>{
    console.log(state,action); //state表示上次的存储state,action表示用户传递过来的那句话
    if(action.type === CHANGE_INPUT_VALUE){
    const newState = JSON.parse(JSON.stringify(state));//对之前的state做一个深拷贝
    newState.inputValue = action.value;
    return newState;
    }else if(action.type === ADD_TODO_ITEM){
    const newState = JSON.parse(JSON.stringify(state));
    newState.list = [...newState.list,newState.inputValue];
    newState.inputValue='';
    return newState;
    }else if(action.type === DELETE_TODO_ITEM){
    const newState = JSON.parse(JSON.stringify(state));
    newState.list.splice(action.index,1);
    return newState;
    }
    return state;
    }

8.使用actionCreator统一创建action

  • 将action的创建放到actionCreators.js进行统一管理,提高代码的可维护性

  • 示例代码:[下述代码将只针对源码中的修改进行介绍]

    //[store/actionCreators.js]
    import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from './actionTypes';
    export const getInputChangeAction = (value) => ({
    type:CHANGE_INPUT_VALUE,
    value
    })
    export const getAddItemAction = () => ({
    type:ADD_TODO_ITEM
    })
    export const getDeleteItemAction = (index) => ({
    type:DELETE_TODO_ITEM,
    index
    })
    //[Todolist.js]
    //引入actionCreators.js
    import {getInputChangeAction,getAddItemAction,getDeleteItemAction} from './store/actionCreators'
    //直接调用actionCreators.js中的方法创建action并传递给store
    handleInputChange(e){
    //创建action
    const action = getInputChangeAction(e.target.value);
    store.dispatch(action); //将action传递给store
    }
    handleButtonClick(){
    const action = getAddItemAction();
    store.dispatch(action);
    }
    handleItemDelete(index){
    const action=getDeleteItemAction(index);
    store.dispatch(action);
    }

9.Redux知识点复习补充

  • Redux在设计和使用时有三个基本原则
    • store是唯一的【上述代码中我们在store/index.js中定义,所有组件均使用这一个store】
    • 只有store能够改变自己的内容【上述代码中,reducer拿到之前的数据并生成新的数据,将新的数据返回给store,store拿到新的数据并更新】
    • Reducer必须是纯函数(什么是纯函数?给定固定的输入,就一定有固定的输出,而且不会有任何副作用——副作用指的是对参数的修改)【上述代码中reducer导出的是函数,且给定了具体的state和action,一定有固定的输出内容,且在函数内部不会修改参数的值】
  • Redux中核心的API
    • createStore:创建store
    • store.dispatch:派发action给store
    • store.getState:获得store中所有的数据内容
    • store.subscribe:订阅store的改变,只要store发生改变,store.subscribe函数接收的回调函数就会被执行

最后

以上就是大方板栗为你收集整理的Redux入门的全部内容,希望文章能够帮你解决Redux入门所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部