使用来自函数的渲染反应Typescript无限循环

时间:2018-09-04 10:47:24

标签: reactjs typescript render

我已经使用了动态状态为每个ListItem赋予一个单独的状态,以供折叠是否打开。但是,由于必须将参数传递给handleClick函数,因此我的渲染正经历无限循环。

我得到的错误是

Lambdas are forbidden in JSX attributes due to their rendering performance impact

它不允许我使用Lambda,所以我不能使用

<ListItem button={true} onClick={() => props.handleClick(index)}>

我想知道是否有办法解决这个问题,以便可以为每个带有索引值的列表项设置handleClick,而不必使其经历无限循环

App.tsx

interface IState {
error: any,
intro: any,
threads: any[],
title: any,
}

export default class App extends React.Component<{}, IState> {
    constructor (props : any) {
        super (props);

        this.state = {
            error: "",
            intro: "Welcome to RedQuick",
            threads: [],
            title: ""
        };

        this.getRedditPost = this.getRedditPost.bind(this)
        this.handleClick = this.handleClick.bind(this)
    }

    public getRedditPost = async (e : any) => {
        e.preventDefault();

        const subreddit = e.target.elements.subreddit.value;
        const redditAPI = await fetch('https://www.reddit.com/r/'+ subreddit +'.json');
        const data = await redditAPI.json();

        console.log(data);

        if (data.kind) {
            this.setState({
                error: undefined,
                intro: undefined,
                threads: data.data.children,
                title: data.data.children[0].data.subreddit.toUpperCase()
            });
        } else {
            this.setState({
                error: "Please enter a valid subreddit name",
                intro: undefined,
                threads: [],
                title: undefined
            });
        }
    }

    public handleClick = (index : any)  => {
        this.setState({ [index]: true });
    }

    public render() {
        return (
            <div>
                <Header 
                    getRedditPost={this.getRedditPost}
                />
                <p className="app__intro">{this.state.intro}</p>
                {
                    this.state.error === "" && this.state.title.length > 0 ?
                    <LinearProgress />:
                    <ThreadList 
                        error={this.state.error}
                        handleClick={this.handleClick}
                        threads={this.state.threads}
                        title={this.state.title}
                    />
                }   
            </div>
        );
    }
}

Threadlist.tsx

<div className="threadlist__subreddit_threadlist">
    <List>
        { props.threads.map((thread : any, index : any) => 
            <div key={index} className="threadlist__subreddit_thread">
                <Divider />
                <ListItem button={true} onClick={props.handleClick(index)}/* component="a" href={thread.data.url}*/ >
                    <ListItemText primary={thread.data.title} secondary={<p><b>Author: </b>{thread.data.author}</p>} />
                    {props[index] ? <ExpandLess /> : <ExpandMore />}
                </ListItem>
                <Collapse in={props[index]} timeout="auto" unmountOnExit={true}>
                    <p>POOP</p>
                </Collapse>
                <Divider />
            </div>
        ) }
    </List> 
</div>

错误:

  

已超过最大更新深度。当一个组件发生这种情况   重复调用componentWillUpdate内的setState或   componentDidUpdate。 React将嵌套更新的数量限制为   防止无限循环。

2 个答案:

答案 0 :(得分:3)

在这里使用currying概念,像这样:

public handleClick = (index : any) = () => {
    this.setState({ [index]: true });
}

并以相同的方式使用handleClick:onClick={props.handleClick(index)}

请查看此答案以获取更多详细信息:What is 'Currying'?

答案 1 :(得分:0)

此问题是onClick需要一个可以处理参数MouseEvent<T> | undefined的函数。但是,调用onClick={handleClick(index)}解析为handleClick(index)在渲染上解析,并且渲染为onClick={undefined}

您需要将onClick处理程序更改为onClick={() => handleClick(index))或将handleClick更改为handleClick = (index) => () => { ... }。 }

第一个选项将标记tslint jsx-no-lambda规则,在这种情况下,您需要使用第二个选项。

尽管应该禁用jsx-no-lamda,但该规则的目的是因为可能会对性能产生影响,因为每个渲染都会创建一个新功能(在Why shouldn't JSX props use arrow functions or bind?中进行了讨论)。但是,这会使代码更难以推理。通常,过早地优化代码以牺牲可读性为代价是不好的。

如果您以后发现昂贵的渲染可以从此优化中受益,那么最好采用可读的解决方案,例如使用memobind

这样的库来进行记忆