1.用RTK和react-redux实现的count
import { configureStore } from "@reduxjs/toolkit";
import countReducer from "./modules/count";
const Store = configureStore({
reducer: {
count: countReducer,
},
});
export default Store;
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "count",
initialState: {
count: 0,
},
reducers: {
addNumberAction(state, { payload }) {
state.count = state.count + payload;
},
subNumberAction(state, { payload }) {
state.count = state.count - payload;
},
},
});
export const { addNumberAction, subNumberAction } = counterSlice.actions;
export default counterSlice.reducer;
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import store from "./store/store";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
import React, { memo } from "react";
import { connect } from "react-redux";
import { addNumberAction, subNumberAction } from "./store/modules/count";
const App = memo((props) => {
const { count, addNumber, subNumber } = props;
const addNumberClick = () => {
addNumber(1);
};
const subNumberClick = () => {
subNumber(1);
};
return (
<div>
<h2>{count}</h2>
<button onClick={addNumberClick}>加1</button>
<button onClick={subNumberClick}>减1</button>
</div>
);
});
const mapStateToProps = (state) => {
return {
count: state.count.count,
};
};
const mapDispatchToProps = (dispatch) => {
return {
addNumber(num) {
dispatch(addNumberAction(num));
},
subNumber(num) {
dispatch(subNumberAction(num));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
RTK就是简单版的store
react-redux就是让组件不直接操作store这个对象,在外面通过connect函数封装了一层,产生了一个组件。
每个组件都要写这个
const mapStateToProps = (state) => {
return {
count: state.count.count,
};
};
const mapDispatchToProps = (dispatch) => {
return {
addNumber(num) {
dispatch(addNumberAction(num));
},
subNumber(num) {
dispatch(subNumberAction(num));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
很麻烦。
2.useSelector() useDispatch()
import React, { memo } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addNumberAction, subNumberAction } from "./store/modules/count";
const App = memo(() => {
/* 1.使用useSelector将redux中store的数据映射到组件中 , 和mapStateToProps很相似*/
const { count } = useSelector((state) => {
return {
count: state.count.count,
};
});
/* 2.使用useDispatch,直接派发action */
const dispatch = useDispatch();
const addNumberClick = () => {
dispatch(addNumberAction(1));
};
const subNumberClick = () => {
dispatch(subNumberAction(1));
};
return (
<div>
<h2>{count}</h2>
<button onClick={addNumberClick}>加1</button>
<button onClick={subNumberClick}>减1</button>
</div>
);
});
export default App;

3.useSelector的浅层比较性
import React, { memo } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addNumberAction, subNumberAction } from "./store/modules/count";
const Home = memo(() => {
const { message } = useSelector((state) => {
return {
message: state.count.message,
};
});
console.log("Home render");
return <h2>Home:{message}</h2>;
});
const App = memo(() => {
/* 1.使用useSelector将redux中store的数据映射到组件中 , 和mapStateToProps很相似*/
const { count } = useSelector((state) => {
return {
count: state.count.count,
};
});
/* 2.使用useDispatch,直接派发action */
const dispatch = useDispatch();
console.log("App render");
const addNumberClick = () => {
dispatch(addNumberAction(1));
};
const subNumberClick = () => {
dispatch(subNumberAction(1));
};
return (
<div>
<h2>{count}</h2>
<button onClick={addNumberClick}>加1</button>
<button onClick={subNumberClick}>减1</button>
<hr></hr>
<Home></Home>
</div>
);
});
export default App;
在app里面点击按钮,app和home都会render。app里面使用的count改变了,渲染是正常的,但是home依赖的message没有改变。
按道理,如果home没有包裹memo,那么app重新渲染,home肯定也会重新渲染。
memo高阶组件包裹起来的组件有相应的特点:
只有props发送该百年的时候,才会重新渲染。
如果home里面没有使用任何state里面的数据,那么点击app的按钮,只有app render。
import React, { memo } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addNumberAction, subNumberAction } from "./store/modules/count";
const Home = memo(() => {
console.log("Home render");
return <h2>Home</h2>;
});
const App = memo(() => {
/* 1.使用useSelector将redux中store的数据映射到组件中 , 和mapStateToProps很相似*/
const { count } = useSelector((state) => {
return {
count: state.count.count,
};
});
/* 2.使用useDispatch,直接派发action */
const dispatch = useDispatch();
console.log("App render");
const addNumberClick = () => {
dispatch(addNumberAction(1));
};
const subNumberClick = () => {
dispatch(subNumberAction(1));
};
return (
<div>
<h2>{count}</h2>
<button onClick={addNumberClick}>加1</button>
<button onClick={subNumberClick}>减1</button>
<hr></hr>
<Home></Home>
</div>
);
});
export default App;
memo 去掉就会home也会渲染。
home里面有useSeletcor,别的组件改变state,它也会重新渲染。
原因:因为默认情况下,useSeletcor监听的是整个state,
只要state发生改变了,组件就会重新渲染。
state:{count:0, message:"hello world"}
app改变了count,home使用的是message,message没有改变
性能不高。
在home修改message,app也会重新渲染。
这个时候,
useSelector的作用是将state映射到组件中:
参数一:将state映射到需要的数据中;
参数二:可以进行比较来决定是否组件重新渲染;(后续讲解)
import React, { memo } from "react";
import { useSelector, useDispatch, shallowEqual } from "react-redux";
import {
addNumberAction,
changeMessageAction,
subNumberAction,
} from "./store/modules/count";
const Home = memo(() => {
/* 本次映射出来的数据和上次映射出来的数据进行比较,看看message有没有改变,只有改变,才让当前组件渲染 */
const { message } = useSelector((state) => {
return {
message: state.count.message,
};
}, shallowEqual);
const dispatch = useDispatch();
console.log("Home render");
const changemessage = () => {
dispatch(changeMessageAction("changed message"));
};
return (
<div>
<h2>Home:{message}</h2>
<button onClick={(e) => changemessage()}>改变message</button>
</div>
);
});
const App = memo(() => {
/* 1.使用useSelector将redux中store的数据映射到组件中 , 和mapStateToProps很相似*/
const { count } = useSelector((state) => {
return {
count: state.count.count,
};
});
/* 2.使用useDispatch,直接派发action */
const dispatch = useDispatch();
console.log("App render");
const addNumberClick = () => {
dispatch(addNumberAction(1));
};
const subNumberClick = () => {
dispatch(subNumberAction(1));
};
return (
<div>
<h2>{count}</h2>
<button onClick={addNumberClick}>加1</button>
<button onClick={subNumberClick}>减1</button>
<hr></hr>
<Home></Home>
</div>
);
});
export default App;
给home的useSelector添加第二个参数shallowEqual,
那么只有返回的这个状态和上次返回的这个状态不同的时候,才会更新组件。
这次,点击app的按钮,也只有app才会渲染。
改变message,也只有home才会渲染。
网友评论