Сразу демка https://codepen.io/lubus/pen/rNBXJRB
В чем проблема:
Я хочу из компонента Timer
получить данные, сколько там натикало в родительский компонент Question
. Пытался забирать это через callback внутри componentWillUnmount()
, чтобы не дергать каждую секунду. Сейчас уже вставил вызов this.props.getTimerData
сразу в tick()
- результат тот же.
В консоли вижу каждую секунду это:
---Question.getTimerData: 00:07 false
Timer.js:45 Uncaught TypeError: this.props.getTimerData is not a function
at Timer.tick (Timer.js:45)
at Timer.js:14
Строка "---Question.getTimerData: 00:07 false
" выводиться из компонента Question, но откуда тогда ошибка?
Код:
child Timer:
import React from 'react';
export default class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {
min: '00',
sec: '00',
timeout: false,
};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
let min = this.state.min;
let sec = this.state.sec;
let timeOut = this.state.timeout;
if (+sec+1 > 59) {
min++;
if (+min < 10) { min='0'+min }
if (+min >= 20) { timeOut = true }
sec = '00';
} else {
sec++;
if (+sec < 10) { sec='0'+sec }
}
this.setState({
min: min,
sec: sec,
timeout: timeOut
});
this.props.getTimerData(this.state.min+':'+this.state.sec, this.state.timeout);
}
render() {
let timerClasses = 'examtimer';
if (this.state.timeout) {
timerClasses = 'examtimer examtimer_overrun';
}
return (
<div className={timerClasses}>
{this.state.min}:{this.state.sec}
</div>
);
}
}
parent Question (упростил для наглядности):
import React from 'react';
import Timer from './Timer';
import questions from '../questions';
export default class Question extends React.Component {
constructor(props) {
super(props);
this.state = {
timerData: null,
timeOut: false
};
}
getTimerData = (timerData, timeOut) => {
this.setState({ timerData: timerData, timeOut: timeOut});
console.log('---Question.getTimerData: ', this.state.timerData, this.state.timeOut);
};
render() {
return(
<div className="exam__timer">
<Timer getTimerData={this.getTimerData} />
<div style={{'display': 'none'}}>
<Timer />
</div>
</div>
);
}
}
package.json:
{
"name": "app",
"version": "0.1.0",
"private": true,
"dependencies": {
"classnames": "^2.2.6",
"react": "^16.10.0",
"react-dom": "^16.10.0",
"react-scripts": "3.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
У вас компонент Timer
используется дважды: один раз с параметром getTimerData
, а второй раз - без
<div style={{'display': 'none'}}>
<Timer />
</div>
Вот во втором и возникает ошибка.
Если пока не понятно, как именно реализовать Timer
- то можно указать дефолтное значение для props
через defaultProps
, а также указать тип через propTypes
для проверки типов. Есть два способа. Первый через static
свойства внутри класса:
class Timer extends React.Component {
static propTypes = {
getTimerData: PropTypes.func
}
static defaultProps = {
getTimerData: () => {}
}
// some code...
}
Второй - через свойства класса после его объявления:
class Timer extends React.Component {
// some code...
}
Timer.propTypes = {
getTimerData: PropTypes.func
};
Timer.defaultProps = {
getTimerData: () => {}
};
Не обязательно указывать defaultProps
и propTypes
, можно указывать и что-то одно.
После того, как Вы укажете значение в defaultProps
для метода getTimerData
- ошибка пропадет, и если не передать в компонент пропсу getTimerData
- будет использоваться дефолтное значение по-умолчанию, в данном примере это просто пустая функция () => {}
, которая ничего не делает.
Для справки:
PropTypes
предоставляет ряд валидаторов, которые могут использоваться для проверки, что получаемые данные корректны. С версии React 15.5 React.PropTypes
были вынесены в отдельный пакет. Необходимо использовать библиотеку prop-types
для проверки типов.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab