分别使用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>
)
}