setState内部构造函数不能正常工作:ReactJS

时间:2017-09-07 12:39:31

标签: reactjs typescript redux react-redux

我正在尝试在React + Redux中运行以下代码但是遇到了未处理的

  

异常'NodeInvocationException:无法读取属性'showText'   null TypeError:无法读取null'

的属性'showText'
import * as React from 'react';
import { NavMenu } from './NavMenu';

import { Component } from 'react';

export interface BlinkState
{
    showText: boolean;
    text: '';
}

type BlinkProps = BlinkState;

class Blink extends React.Component<BlinkProps, BlinkState> {
    constructor(props: BlinkProps) {
        super(props);
        //this.state = { showText: true };

        this.setState({ showText: true, text: props.text });

        // Toggle the state every second
        setInterval(() => {
            this.setState(previousState => {
                return { showText: !previousState.showText };
            });
        }, 1000);
    }

    render() {
        let display = this.state.showText ? this.props.text : ' ';
        return <div>{ display }</div>;
    }
}


export class Layout extends React.Component<{}, {}> {
    public render() {
        return <div className='container-fluid'>
            <Blink showText=false text='I love to blink' />
        </div>;
    }
}

我只想弄清楚如何使用传入的道具渲染Blink copmonent ......

2 个答案:

答案 0 :(得分:3)

您错过了基本的事情,使用constructorsetState,使用constructor来初始化状态值,使用setState来更新状态值,所以在`constructor中使用setState没有任何意义。

更好的方法是,在构造函数中初始化状态并运行时间使用componentDidMount生命周期方法,也不要忘记在卸载组件之前停止时间,清除它使用componentWillUnmount生命周期方法。

像这样编写组件:

class Blink extends React.Component<BlinkProps, BlinkState> {
    constructor(props: BlinkProps) {
        super(props);
        this.state = { showText: false };
    }

    componentDidMount(){
        this.timer = setInterval(() => {
            this.setState(previousState => {
                return { showText: !previousState.showText };
            });
        }, 1000);
    }

    componentWillUnmount(){
        clearInterval(this.timer)
    }

    render() {
        let display = this.state.showText ? this.props.text : ' ';
        return <div>{ display }</div>;
    }
}

工作代码:

class Blink extends React.Component {
    constructor(props) {
        super(props);
        this.state = { showText: true, text: props.text };
    }

    componentDidMount(){
        this.timer = setInterval(() => {
            this.setState(prev => {
                return { showText: !prev.showText };
            });
        }, 1000);
    }

    componentWillUnmount(){
        clearTimer(this.timer)
    }

    render() {
        let display = this.state.showText ? this.props.text : ' ';
        return <div>Hello { display }</div>;
    }
}

class Layout extends React.Component{
    render() {
        return <div className='container-fluid'>
            <Blink text='I love to blink' />
        </div>;
    }
}

ReactDOM.render(<Layout/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'/>

答案 1 :(得分:2)

您不应指定要在constructor中使用的操作或使用setStateconstructor应该用于简单地设置初始状态。

此外,您可能需要更新state text,因为它是基于道具设置的。在componentWillReceiveProps

中执行

当您使用setInterval时,请确保在clearInterval

componentUnmounts
constructor(props: BlinkProps) {
        super(props);
        this.state = { showText: true, text: props.text };

    }
componentWillReceiveProps(nextProps) {
     this.setState({text: nextProps.text});
}
componentDidMount() {
      // Toggle the state every second
        this.interval = setInterval(() => {
            this.setState(previousState => {
                return { showText: !previousState.showText };
            });
        }, 1000);
}
componentWillUnmount() {
    clearInterval(this.interval)
}