分别使用redux
和react-redux
来实现todoList操作。
使用useContext
, useReducer
, createContext
来代替redux, 计数器案例
1. 安装
npm install redux react-redux --save
2. store文件夹下文件。
Action.js
(提供各个action对象的函数),
ActionTypes.js
(action中type常量),
index.js
(提供访问数据),
Reducer.js
(对数据的操作)
网络异常,图片无法展示
|
// Action.js import { ADDITEM, DELETEITEM } from './ActionTypes' // 增加的action export const addHandle = () => { return { type: ADDITEM } } // 删除的action export const deleteHandle = () => { return { type: DELETEITEM } }
// ActionTypes.js export const ADDITEM = "addItem" export const DELETEITEM = "deleteItem"
// index.js import { createStore } from "redux"; import reducer from './Reducer' // 参数二,表示使用redux-tools插件 const store = createStore( reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ); export default store;
// reducer.js import { ADDITEM, DELETEITEM } from './ActionTypes' let defaultState = { defaultValue: "我是默认值", list: [ "今天天气真好啊", "昨天天气也好啊" ] } export default function reducer(state = defaultState, action) { if (action.type === ADDITEM) { let newState = JSON.parse(JSON.stringify(state)) newState.list.push(action.value) return newState } if (action.type === DELETEITEM) { let newState = JSON.parse(JSON.stringify(state)) newState.list.splice(action.index, 1) return newState } return state }
3. 使用redux
import React, { Component, createRef } from 'react'; import store from './store'; import { addHandle, deleteHandle } from './store/Action' export default class TestRedux extends Component { constructor(props) { super(props) // this.state不能等于非Object的值 this.state = store.getState(); this.inputDom = createRef(); } componentDidMount() { store.subscribe(() => this.setState(store.getState())) } // 增加 addItem = () => { if (this.inputDom.current) { store.dispatch({ ...addHandle(), value: this.inputDom.current.value }) } } // 删除 deleteItem = (index) => { console.log(index) store.dispatch({ ...deleteHandle(), index }) } render() { return <div> <input type="text" ref={this.inputDom} placeholder={this.state.defaultValue} /> <button onClick={this.addItem}>增加</button> <ul> { this.state.list && this.state.list.map((item, index) => <li onClick={() => this.deleteItem(index)} key={index}>{item}</li>) } </ul> </div> } }
4. 使用react-redux的内置组件Provider包裹需要使用store中数据的组件
通过Provider组件(提供store)包裹的组件,都可以访问store中的值。
// App.js import TestRedux from './TestRedux'; import { Provider } from 'react-redux' import store from "./store"; <Provider store={store}> <TestRedux></TestRedux> </Provider>
5. 使用react-redux的内置函数connect包裹需要使用store中数据的组件
使用connect(stateToProps, dispatchToProps)(组件)包裹使用store的组件,该函数传递一个state映射函数和dispatch映射函数。都被映射到props
上。
注意: 如果dispatch操作需要访问组件中的数据,我们可以通过事件传递参数。
// TestRedux.jsx import React, { createRef } from 'react'; import { connect } from 'react-redux'; import { addHandle, deleteHandle } from './store/Action' const TestRedux = (props) => { const inputDom = createRef(); const { list, defaultValue, addItem, deleteItem } = props return (<div> <input type="text" ref={inputDom} placeholder={defaultValue} /> <button onClick={() => addItem(inputDom)}>增加</button> <ul> { list && list.map((item, index) => <li onClick={() => deleteItem(index)} key= {index}>{item}</li>) } </ul> </div>) } // 将store中得值映射到props上。 const stateToProps = (state) => { return { defaultValue: state.defaultValue, list: state.list } } // 将事件映射到props上 const dispatchToProps = (dispatch) => { return { // 增加 // 如果我们需要在组件中获取到特定的值,例如:dom。我们可以通过事件传递参数。 addItem(inputDom) { if (inputDom.current) { dispatch({ ...addHandle(), value: inputDom.current.value }) } }, // 删除 deleteItem(index) { dispatch({ ...deleteHandle(), index }) } } } export default connect(stateToProps, dispatchToProps)(TestRedux)
6. 使用useContext和useReducer来代替redux
我们在父组件中使用createContext()
来提供state和dispatch,使用useReducer(reducer, initState)
来做数据处理操作
通过useContext()
来获取Provider
组件包裹的组件中使用state,dispatch值做出一些操作。
// UpDown.jsx-----父组件 import React, { createContext, useReducer } from "react"; export const countContext = createContext({}); export const UPCOUNT = "UPCOUNT" export const DOWNCOUNT = "DOWNCOUNT" function reducer(state, action) { switch (action.type) { case UPCOUNT: return action.value; case DOWNCOUNT: return action.value default: return state; } } export default function UpDown(props) { const [count, dispatch] = useReducer(reducer, 0) return ( // 注意:这里的value传递的是对象 <countContext.Provider value={{ count, dispatch }}> {props.children} </countContext.Provider> ) }
// Operator.js ----子组件 import { useContext } from "react"; import { DOWNCOUNT, countContext, UPCOUNT } from './UpDown' export default function Operator(props) { const { count, dispatch } = useContext(countContext); return ( <div> <p>当前计数:{count}</p> <button onClick={() => dispatch({ type: UPCOUNT, value: count + 1 })}>增加</button> <button onClick={() => dispatch({ type: DOWNCOUNT, value: count - 1 })}>减少</button> </div> ) }