reactjs - 更新 redux 商店时应用重新渲染
问题描述
每次我发送一个动作并更新我的商店时,我的整个应用程序都会重新呈现。我假设我的 connect/mapDispatchToProps 函数做错了什么?在 App.js 中{ ...actions }
作为第二个参数传递给我的函数是否正确?connect
这是我的代码:
class App extends Component {
componentDidMount() {
this.props.fetchPages(api.API_PAGES);
this.props.fetchPosts(api.API_POSTS);
window.addEventListener('resize', () => {
this.props.resizeScreen(window.innerWidth);
});
}
render() {
return (
<div>
{this.props.app.showIntro && <Intro {...this.props} endIntro={this.props.endIntro} />}
{!this.props.pages.isFetching && this.props.pages.data &&
<div>
<Navbar {...this.props} />
<Layout {...this.props}>
<Switch location={this.props.location}>
<Route
path={routes.HOME}
exact
component={() => (
<Home {...this.props} />
)}
/>
<Route
path={routes.ABOUT}
component={() => (
<About {...this.props} />
)}
/>
<Route
path={routes.NEWS}
exact
component={() => (
<News {...this.props} />
)}
/>
<Route
component={NotFound}
/>
</Switch>
</Layout>
</div>
}
</div>
);
}
}
function mapStateToProps(state) {
return {
app: state.app,
pages: state.pages,
posts: state.posts
};
}
export default withRouter(connect(
mapStateToProps,
{ ...actions }
)(App));
动作/index.js
export function resizeScreen(screenWidth) {
return {
type: types.RESIZE_SCREEN,
screenWidth
};
}
export function endIntro() {
return {
type: types.END_INTRO,
showIntro: false
};
}
export function toggleNav(bool) {
return {
type: types.TOGGLE_NAV,
navOpen: bool
};
}
export function toggleVideoPlayer(bool) {
return {
type: types.TOGGLE_VIDEO_PLAYER,
videoIsPlaying: bool
};
}
export function toggleScroll(bool) {
return {
type: types.TOGGLE_SROLL,
disableScroll: bool
};
}
// pages
function requestPages() {
return {
type: types.REQUEST_PAGES
};
}
function receivePages(data) {
return {
type: types.RECEIVE_PAGES,
data
};
}
// posts
function requestPosts() {
return {
type: types.REQUEST_POSTS
};
}
function receivePosts(data) {
return {
type: types.RECEIVE_POSTS,
data
};
}
// creators
export function fetchPages(path) {
return (dispatch, getState) => {
const { pages } = getState();
if (pages.isFetching) return;
dispatch(requestPages());
fetch(`${process.env.API_URL}${path}`)
.then(response => response.json())
.then(json => dispatch(receivePages(json)));
};
}
export function fetchPosts(path) {
return (dispatch, getState) => {
const { posts } = getState();
if (posts.isFetching) return;
dispatch(requestPosts());
fetch(`${process.env.API_URL}${path}`)
.then(response => response.json())
.then(json => dispatch(receivePosts(json)));
};
}
减速器/app.js:
const initialState = {
screenWidth: typeof window === 'object' ? window.innerWidth : null,
showIntro: true,
navOpen: false,
videoIsPlaying: false,
disableScroll: false
};
export default function app(state = initialState, action) {
switch (action.type) {
case RESIZE_SCREEN: {
return {
...state,
screenWidth: action.screenWidth
};
}
case TOGGLE_NAV: {
return {
...state,
navOpen: !state.navOpen
};
}
case END_INTRO: {
return {
...state,
showIntro: false
};
}
case TOGGLE_VIDEO_PLAYER: {
return {
...state,
videoIsPlaying: !state.videoIsPlaying
};
}
case TOGGLE_SCROLL: {
return {
...state,
disableScroll: !state.disableScroll
};
}
default: {
return state;
}
}
}
reducers/posts.js 类似于 reducers/pages.js:
const initialState = {
isFetching: false
};
export default function posts(state = initialState, action) {
switch (action.type) {
case REQUEST_POSTS: {
return {
...state,
isFetching: true
};
}
case RECEIVE_POSTS: {
return {
...state,
isFetching: false,
data: action.data
};
}
default: {
return state;
}
}
}
解决方案
如果您在每次 redux 更新时有太多应用程序重新渲染的问题,它有助于使用更多连接的组件并限制传递给每个组件的状态量。我看到您正在将道具向下传播到每个页面,这很方便,但是重新渲染效率低下的常见原因。
<Home {...this.props} />
<About {...this.props} />
<News {...this.props} />
这可能会导致向这些组件中的每一个传递太多数据,并且每个 redux 操作都会导致整个页面重新渲染。
我看到的另一个潜在问题是您使用内联匿名函数作为路由的组件回调
<Route
path={routes.ABOUT}
component={() => (
<About {...this.props} />
)}
/>
我不确定 React Router 是如何在这里工作的,但一个潜在的问题是,每次路由器重新渲染时,这些匿名函数都会再次创建全新的。React 会将它们视为一个新组件并强制重新渲染。您可以通过将这些组件中的每一个都设置为一个连接组件来拉入它们自己的道具,然后像这样更新路由器来解决这个问题
<Route
path={routes.ABOUT}
component={ConnectedAbout}
/>
推荐阅读
- multithreading - 图片未在视图控制器启动 Swift 时加载
- html - 为什么 HTML 可拖动元素与父背景一起拖动?
- python - if python语句中的多个and
- angular - 如何在浏览器中有效地渲染数百个角高图而不会崩溃?
- reactjs - 使 Antd 的 TreeSelect 和 Tree 组件可访问(使用 tab 键时突出显示)
- c# - 为什么要计算通过聚合实现的 mongodb C# LINQ 驱动程序?
- ansible - LooseVersion 实例没有属性版本 - openshift 错误中的 awx 安装
- html - 如何将带有格式的文本区域数据发送到数据库并以相同的方式检索它
- javascript - 单击提交后如何将文本从输入设置到另一个元素?
- reactjs - socket.io 中的一个客户端的连接事件被无限次触发