Redux安装命令:npm i redux react-redux --save-dev

Redux流程:首先我们需要一个store,然后组件从store中去取数据,如果组件想改变store里的数据——首先需要派发一个action给store,store把action和之前的数据一起给到reducer,reducer结合action和之前的数据返回一个新数据给store,store更新自己的数据后告诉组件数据被更新,页面就会跟着联动。

创建Store目录:

        

父组件TodoList.js以及子组件TodoListUI.js部分(拆分代码实现redux集中管理数据,用无状态的UI组件——子组件做渲染,容器组件——父组件做逻辑)

//父
import React, { Component } from 'react';
import TodoListUI from './TodoListUI';
import axios from 'axios'
import store from './store'
import { getInputChangeAction, getAddItemAction, getDeleteItemAction, initListAction } from './store/actionCreators'

class TodoList extends Component {
    //类中必有constructor函数 而且会最先执行
    constructor(props) {
        super(props);
        this.state = store.getState();
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleStoreChange = this.handleStoreChange.bind(this);
        this.handleButtonSubmit = this.handleButtonSubmit.bind(this);
        this.handleItemDelete = this.handleItemDelete.bind(this);
    }
    componentDidMount() {
        //3.固定——订阅store的变化,只要store中的数据改变,这个方法就会被执行
        store.subscribe(this.handleStoreChange)
        //请求数据存到store中 1.action给store传话 
        axios.get('/api/list').then((res) => {
            const action = initListAction(res.data)
            store.dispatch(action);//store.dispatch方法把action派发给store
        }).catch((err) => {
            console.log(err);
        })
    }
    //4.固定——store已被改变后要做的事——当感知到store数据变化的时候,用setState调用store.getState方法,从store里重新取数据,替换掉当前组件中的数据
    handleStoreChange() {
        this.setState(store.getState(), () => {
            console.log(this.state);//打印出的就是最新的数据
            console.log(store.getState());//打印出的就是最新的数据
        })
    }
    //改变input框值 1.action给store传话 
    handleInputChange(e) {
        // const action = {//store!帮我改变inputValue的值,值为e.target.value
        //     type: change_input_value,
        //     value: e.target.value
        // }
        const action = getInputChangeAction(e.target.value)
        store.dispatch(action);//store.dispatch方法把action派发给store,store再默默传给reducer
    }
    //添加 1.action给store传话
    handleButtonSubmit() {
        const action = getAddItemAction();
        store.dispatch(action)
    }
    //删除 1.action给store传话
    handleItemDelete(index) {
        const action = getDeleteItemAction(index)
        store.dispatch(action)
    }
    render() {
        return (
            <TodoListUI
                inpuValue={this.state.inpuValue}
                handleInputChange={this.handleInputChange}
                handleButtonSubmit={this.handleButtonSubmit}
                list={this.state.list}
                handleItemDelete={this.handleItemDelete} />
        )
    }
}
export default TodoList;

//子
import React from 'react';
import 'antd/dist/antd.css';
import { Input, Button, List } from 'antd';

const TodoList = (props) => {
  return (
    <div style={{ marginTop: "10px", marginLeft: "10px" }}>
      <div>
        <Input
          value={props.inputValue}
          placeholder="todo info"
          style={{ width: "300px", marginRight: "10px" }}
          onChange={props.handleInputChange}></Input>
        <Button type="primary" onClick={props.handleButtonSubmit}>提交</Button>
      </div>
      <List
        style={{ marginTop: "10px", width: "370px" }}
        bordered
        dataSource={props.list}
        renderItem={(item, index) =>
          <List.Item
            onClick={() => { props.handleItemDelete(index) }}>
            {item}
          </List.Item>
        }
      />
    </div>
  )
}
export default TodoList;

但是,如果用了provider和connect这两个react-redux的核心api,那么将会在组件中定义mapStateToProps和mapDispatchToProps规则,并且组件可以因此写成无状态UI组件,以便于提高性能。主入口文件index.js和父组件TodoList.js将为以下代码:

//*** src > index.js
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
import reportWebVitals from './reportWebVitals';
//1.react-redux的第一个核心api是Provider,它连接store,provider内部的组件都有能力获取到store的内容了
import { Provider } from 'react-redux';
import store from './store'

const App = (
  <Provider store={store}>
    <TodoList />
  </Provider>
)

ReactDOM.render(
  App,
  document.getElementById('root')
);

reportWebVitals();

//*** src > TodoList.js
import React, { Component } from 'react';
//*connect是react-redux的第二个核心Api,通过connect方法获取store的数据
import { connect } from 'react-redux';
import { changeInputAction, handleSubmitAction, handleDeleteAction } from './store/actionCreators'

//改为无状态UI组件
const TodoList = (props) => {
  const { inputValue, changeInputValue, handleSubmitButton, handleDeleteItem, list } = props;
  return (
    <div>
      <div>
        <input value={inputValue} onChange={changeInputValue} type="text" />
        <button onClick={handleSubmitButton}>提交</button>
      </div>
      <ul>
        {
          list.map((item, index) => {
            return <li onClick={() => { handleDeleteItem(index) }} key={index}>{item}</li>
          })
        }
      </ul>
    </div>
  )
}

//本来是有状态组件
// class TodoList extends Component {
//   render() {
//     const { inputValue, changeInputValue, handleSubmitButton, handleDeleteItem, list } = this.props;
//     return (
//       <div>
//         <div>
//           <input value={inputValue} onChange={changeInputValue} type="text" />
//           <button onClick={handleSubmitButton}>提交</button>
//         </div>
//         <ul>
//           {
//             list.map((item, index) => {
//               return <li onClick={() => { handleDeleteItem(index) }} key={index}>{item}</li>
//             })
//           }
//         </ul>
//       </div>
//     )
//   }
// }

//3.1规则1: store里的数据和组件的数据的关系;函数中传的state就是store里的数据
const mapStateToProps = (state) => {
  return {
    inputValue: state.inputValue,
    list: state.list
  }
}
//3.2规则2: 组件里props如何对store里的数据做修改和store.dispatch方法做关联;函数中传的dispatch就是让    changeInputValue函数可以调用store.dispatch方法改变数据
const mapDispatchToProps = (dispatch) => {
  return {
    changeInputValue(e) {
      const action = changeInputAction(e.target.value);
      dispatch(action);
    },
    //添加
    handleSubmitButton() {
      const action = handleSubmitAction();
      dispatch(action);
    },
    //删除
    handleDeleteItem(index) {
      const action = handleDeleteAction(index);
      dispatch(action)
    }
  }

}
//2.让TodoList这个组件和store做关联,没问题,因为在index.js主入口中,Provider组件包裹了TodoList组件
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);

store>index.js部分:

import { createStore } from 'redux';
import reducer from './reducer';
//**当组件调用store.dispatch(action)方法时,store.js不知道要干什么,于是就把previousState和action默默传给reducer.js;之后 reducer.js返回newState给store,也是store在改变数据
//createStore创建store
const store = createStore(//把reducer传给store,store才知道数据有多少
  reducer,//如果浏览器安装了redux的devtools那么就使用
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
export default store;

actionCreators.js部分:

//action对象是写在actionCreater里面的
import { change_input_value, add_todo_item, delete_todo_item, init_list_action } from './actionTypes'

export const getInputChangeAction = (val) => ({
  type: change_input_value,
  //value为action对象的属性
  value: val
})
export const getAddItemAction = () => ({
  type: add_todo_item
})
export const getDeleteItemAction = (index) => ({
  type: delete_todo_item,
  index
})
//函数接收组件传的参数——这里为axios请求的数据,返回对象就是我们要在reducer.js中使用的的action
export const initListAction = (data) => ({
  type: init_list_action,
  data
})

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'
export const init_list_action = 'init_list_action'

reducer.js部分 

//创建reducer——存储数据的笔记本
import { change_input_value, add_todo_item, delete_todo_item, init_list_action } from './actionTypes'

const defaultState = {//store的默认值
  inputValue: '',
  list: []
}

const reducer = (state = defaultState, action) => {
  //2.reducer可以接收state,但是绝不能修改state,这也是为什么深拷贝
  if (action.type === change_input_value) {
    const newState = JSON.parse(JSON.stringify(state));//深拷贝
    newState.inputValue = action.value;//改变store中inputValue的值
    return newState//newState被返回给了store
  }
  //增加
  if (action.type === add_todo_item) {
    const newState = JSON.parse(JSON.stringify(state));//深拷贝
    newState.inputValue && newState.list.push(newState.inputValue)//将目前的inputValue放进列表中
    newState.inputValue = "";//并且把input框清空
    return newState//newState被返回给了store
  }
  //删除
  if (action.type === delete_todo_item) {
    const newState = JSON.parse(JSON.stringify(state));
    newState.list.splice(action.index, 1);
    return newState//newState被返回给了store
  }
  //axios请求的数据作为list的值
  if (action.type === init_list_action) {
    const newState = JSON.parse(JSON.stringify(state));//深拷贝
    newState.list = action.data;
    return newState//newState被返回给了store
  }
  return state
}

export default reducer;

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐