当前位置: 首页 > 面试题库 >

在React中无限渲染

黄兴业
2023-03-14
问题内容

我在弄清楚为什么我的应用程序执行无尽渲染时遇到问题。

在内部,我的有状态组件,我正在componentDidMount方法中调用redux动作(调用componentWillMount也可以进行无尽渲染)

class cryptoTicker extends PureComponent {
  componentDidMount() {
    this.props.fetchCoin()
    // This fetches some 1600 crypto coins data,Redux action link for the same in end
  }

  render() {
    return (
      <ScrollView>
        <Header />
        <View>
          <FlatList
            data={this.state.searchCoin ? this.displaySearchCrypto : this.props.cryptoLoaded}
            style={{ flex: 1 }}
            extraData={[this.displaySearchCrypto, this.props.cryptoLoaded]}
            keyExtractor={item => item.short}
            initialNumToRender={50}
            windowSize={21}
            removeClippedSubviews={true}
            renderItem={({ item, index }) => (
              <CoinCard
                key={item["short"]}
              />
            )} 
          />
        </View>
      </ScrollView>
    )
  }
}

在CoinCard中,我实际上不做任何事情(在Flat列表内注意CoinCard)

class CoinCard extends Component {
  render () { 
    console.log("Inside rende here")
    return (
        <View> <Text> Text </Text>  </View>
    )  
  }
}

现在,当我控制台登录我的硬币卡渲染时,我可以 在此处* 看到 Inside rende的 无限日志 *

[问题:] 谁能帮我弄清楚为什么会这样吗?

您可以单击此处查看我的操作,然后单击此处查看我的减速器。

[更新:] 如果要克隆并自己查看,我的存储库就在这里。

[更新:2]
:我已经在github上推送了上面的共享代码,它仍然会记录无尽的console.log语句(如果可以克隆,运行并移回此commit)。

[Update:3]: 当我指的是无尽的渲染时,我也不再使用<ScrollView />in <FlatList />,我的意思是说它是无休止的(&不必要地)将相同的props传递给子组件(<Coincard />),如果我使用PureComponent,它将不会无休止地记录日志在render () {但是在中componentWillRecieveProps,如果我这样做console.log(nextProps),我可以看到相同的日志一遍又一遍


问题答案:

就像izb提到的那样,pb的根本原因是在纯组件上进行的业务调用,而该组件只是被加载了。这是因为您的组件做出了业务决策(<=>“我决定何时必须在自己体内显示某些内容”)。在React中这不是一个好习惯,甚至在使用redux时也不是。该组件必须尽可能地愚蠢,甚至不能决定做什么和何时进行。

正如我在您的项目中看到的那样,您没有正确处理组件和容器的概念。您的容器中不应包含任何逻辑,因为它应该只是愚蠢的纯组件的包装。像这样:

import { connect, Dispatch } from "react-redux";
import { push, RouterAction, RouterState } from "react-router-redux";
import ApplicationBarComponent from "../components/ApplicationBar";

export function mapStateToProps({ routing }: { routing: RouterState }) {
    return routing;
}

export function mapDispatchToProps(dispatch: Dispatch<RouterAction>) {
    return {
        navigate: (payload: string) => dispatch(push(payload)),
    };
}
const tmp = connect(mapStateToProps, mapDispatchToProps);
export default tmp(ApplicationBarComponent);

和匹配的组件:

import AppBar from '@material-ui/core/AppBar';
import IconButton from '@material-ui/core/IconButton';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import { StyleRules, Theme, withStyles, WithStyles } from '@material-ui/core/styles';
import Tab from '@material-ui/core/Tab';
import Tabs from '@material-ui/core/Tabs';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MenuIcon from '@material-ui/icons/Menu';
import autobind from "autobind-decorator";
import * as React from "react";
import { push, RouterState } from "react-router-redux";

const styles = (theme: Theme): StyleRules => ({
  flex: {
    flex: 1
  },
  menuButton: {
    marginLeft: -12,
    marginRight: 20,
  },
  root: {
    backgroundColor: theme.palette.background.paper,
    flexGrow: 1
  },
});
export interface IProps extends RouterState, WithStyles {
  navigate: typeof push;
}

@autobind
class ApplicationBar extends React.PureComponent<IProps, { anchorEl: HTMLInputElement | undefined }> {
  constructor(props: any) {
    super(props);
    this.state = { anchorEl: undefined };
  }
  public render() {

    const auth = true;
    const { classes } = this.props;
    const menuOpened = !!this.state.anchorEl;
    return (
      <div className={classes.root}>
        <AppBar position="fixed" color="primary">
          <Toolbar>
            <IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
              <MenuIcon />
            </IconButton>
            <Typography variant="title" color="inherit" className={classes.flex}>
              Title
            </Typography>

            <Tabs value={this.getPathName()} onChange={this.handleNavigate} >
              {/* <Tabs value="/"> */}
              <Tab label="Counter 1" value="/counter1" />
              <Tab label="Counter 2" value="/counter2" />
              <Tab label="Register" value="/register" />
              <Tab label="Forecast" value="/forecast" />
            </Tabs>

            {auth && (
              <div>
                <IconButton
                  aria-owns={menuOpened ? 'menu-appbar' : undefined}
                  aria-haspopup="true"
                  onClick={this.handleMenu}
                  color="inherit"
                >
                  <AccountCircle />
                </IconButton>
                <Menu
                  id="menu-appbar"
                  anchorEl={this.state.anchorEl}
                  anchorOrigin={{
                    horizontal: 'right',
                    vertical: 'top',
                  }}
                  transformOrigin={{
                    horizontal: 'right',
                    vertical: 'top',
                  }}
                  open={menuOpened}
                  onClose={this.handleClose}
                >
                  <MenuItem onClick={this.handleClose}>Profile</MenuItem>
                  <MenuItem onClick={this.handleClose}>My account</MenuItem>
                </Menu>
              </div>
            )}
          </Toolbar>
        </AppBar>
      </div >
    );
  }
  private getPathName(): string {
    if (!this.props.location) {
      return "/counter1";
    }
    return (this.props.location as { pathname: string }).pathname;
  }
  private handleNavigate(event: React.ChangeEvent<{}>, value: any) {
    this.props.navigate(value as string);
  }

  private handleMenu(event: React.MouseEvent<HTMLInputElement>) {
    this.setState({ anchorEl: event.currentTarget });
  }

  private handleClose() {
    this.setState({ anchorEl: undefined });
  }
}
export default withStyles(styles)(ApplicationBar);

然后,您会告诉我:“但是,我在哪里发起可以填满列表的呼叫?” 好吧,我在这里看到您使用redux-
thunk(我更喜欢redux可观察的…学习起来更复杂,但是waaaaaaaaaaaaaaaaaaay更强大),然后应该将其重做,从而启动此调度!

总结一下:

  • 组件:最愚蠢的元素,通常只应具有render方法,以及一些其他使用户事件冒泡的方法处理程序。此方法仅负责向用户显示其属性。除非您拥有仅属于此组件的视觉信息(例如,弹出窗口的可见性),否则不要使用状态。显示或更新的所有内容均来自上方:更高级别的组件或容器。它没有决定更新自己的值。充其量,它会处理子组件上的用户事件,然后在上面的另一个事件中冒泡,然后……也许在某些时候,其容器会返回一些新属性!
  • 容器:非常愚蠢的逻辑,它包含将顶级组件包装到redux中,以便将事件插入到动作中,并将存储的某些部分插入到属性中
  • Redux thunk(或可观察到的redux):它处理整个用户应用程序逻辑。这个家伙是唯一知道何时触发什么的人。如果前端的一部分必须包含复杂性,那就是这个!
  • 精简器:定义如何组织存储中的数据以使其尽可能易于使用。
  • 存储:理想情况下,每个顶层容器一个,唯一一个包含必须向用户显示数据的容器。没人应该。

如果遵循这些原则,您将永远不会面临任何问题,例如“为什么要两次被打扰?以及……是谁打出来的?为什么在这一刻呢?”

其他:如果您使用redux,请使用不变性框架。否则,您可能会遇到问题,因为reducer必须是纯函数。为此,您可以使用一种流行的immutable.js,但一点都不方便。而后来的驱逐剂实际上是一个杀手er:沉浸式(作者或暴民制造)。



 类似资料:
  • 问题内容: 我在尝试使用数据数组呈现元素时遇到问题。在的下面的代码中,可以正常工作,但列表项未出现。 我究竟做错了什么?请随时指出并非最佳做法的任何内容。 问题答案: GoshaArinich是正确的,您应该返回您的元素。但是,在这种情况下,您应该在浏览器控制台中收到讨厌的红色警告 数组或迭代器中的每个子代都应具有唯一的“键”道具。 因此,您需要在列表中添加“键”: 或使用es6 箭头功能放下并做

  • 如何防止以下错误: 太多的重新渲染。React限制渲染的数量,以防止无限循环。' 我刚刚将一个基于类的组件更改为功能组件,但它不起作用 我的源代码 我只是将一个基于类的组件更改为功能组件,我得到了这些错误。 0个 如何防止以下错误: 太多的重新渲染。React限制渲染的数量,以防止无限循环。'

  • 这是来自物料界面的模板。我从GitHub的注册中选择了这个模板,我只导入了useState并尝试使用它。 它抛出“太多的重新渲染。React限制渲染数量以防止无限循环材质”, 我尝试过使用反应钩子,因为我不能实现类。

  • 当我试图设置状态,然后得到一个错误。错误:太多的重新渲染。React限制渲染的数量以防止无限循环。 我已经用

  • 我正在尝试创建登录表单,但出现了此错误。 任何人都可以解释为什么会发生此错误?? 我是新来的反应本土。 忽略这个(只是为了加量)= =我得补充一些没用的句子因为StackOverflow给我< code > '看起来你的帖子大部分是代码;请再补充一些细节。(对这个stackoverflow错误感到非常沮丧)

  • 我创建了一个需要在应用程序的多个部分中单独显示的组件-(在我的导航内部、主页和单独的路由上)。因此,我在此组件中的一个use中进行了所有操作调度(用于读取数据的api调用)效果: 如您所见,此效果应该只运行一次(当组件装载时)。 在其他任何地方,我都不会在此组件内部或外部调度这些特定操作。 该组件在3个位置渲染(导航内部、其自身的时间路径和主组件内部)。我可以在导航内部同时在时间上渲染它,没有问题