我有一个带有一个元素列表的滑轨-当我导航到另一个容器并向后导航时-道具几乎丢失了吗?我收到以下错误。
错误:
TypeError: Cannot read property 'props' of null
const actionLength = activeRail.props.children.length - 1;
const later = () => {
----> callback.apply(context, callbackArgs)
timeout = null
}
我不确定是什么引起了这个问题。
这是我的代码:
import React, { Component } from 'react';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import key from 'keymaster';
import posed, { PoseGroup } from 'react-pose';
// import { fetchingPageData } from '../../actions';
import channelData from '../../data/channel-data';
import "./styles.scss";
// components
import MusicCard from '../../components/MusicCard/';
import Card from '../../components/JioCardAnimated/';
import TimeAndDate from '../../components/TimeAndDate';
import NotificationCentre from '../NotificationCentre';
// rails
import {accountsRail} from './rails/accounts';
import {searchRail} from './rails/search';
import {homeRail} from './rails/home';
import {onNowRail} from './rails/on-now';
import {moviesRail} from './rails/movies';
import {showsRail} from './rails/shows';
import {musicRail} from './rails/music';
import {appsRail} from './rails/apps';
import {gamesRail} from './rails/games';
import {myFilesRail} from './rails/my-files';
import {settingsRail} from './rails/settings';
function throttle(callback, wait, context = this) {
let timeout = null
let callbackArgs = null
const later = () => {
callback.apply(context, callbackArgs)
timeout = null
}
return function() {
if (!timeout) {
callbackArgs = arguments
timeout = setTimeout(later, wait)
}
}
}
const colors = [
'#1030a4'
];
const Item = posed.div({
initialPose: 'closed',
hidden: {
height: "155px",
opacity: 0,
delay: 0
},
closed: {
height: "155px",
opacity: 1,
delay: 0
},
open: {
height: "650px",
opacity: 0.6
}
});
const Rail = posed.div({
open: {
opacity: 1,
staggerChildren: 50
},
closed: {
opacity: 0,
delay: 50
}
});
const Buddy = posed.div({
STATIC: {
x: 0,
y: 0,
width: 15,
background: ({color}) => `${color}`,
scale:1,
opacity:1,
transition: {
type: 'spring',
}
},
DOWN: {
x: 0,
y: 10,
width: 15,
background: ({color}) => `${color}`,
scale: 0.9,
opacity: 1,
transition: {
type: 'spring'
}
},
UP: {
x: 0,
y: -10,
width:20,
background: ({color}) => `${color}`,
scale:0.9,
opacity:1,
transition: {
type: 'spring'
},
},
EXPANDED: {
x: -155,
y: 0,
width: 15,
background: ({color}) => `${color}`,
scale: 0.3,
opacity: 0,
transition: {
type: 'spring',
decay: 5,
x: { duration: 100 }
}
},
scrolled: {
y: ({ target }) => target,
transition: { type: 'spring' }
},
});
const cardSizes = {
small: 212 + 30,
large: 568 + 30,
music: 303 + 30
};
class MainMenu extends Component {
constructor(props) {
super(props);
this.className = this.keyScope = 'main-menu';
this.rails=[];
//Base Rails
this.baseRails = [
accountsRail,
searchRail,
homeRail,
onNowRail,
moviesRail,
showsRail,
musicRail,
appsRail,
gamesRail,
myFilesRail,
settingsRail,
];
this.state = {
active: false,
indexX: 1,
indexY: 1, // 0,
menuItems: channelData,
isExpanded: false,
expanding: false,
expandDelay: 800,
buddy: 'STATIC',
rails: [...this.baseRails],
transform: cardSizes.small,
notifications:[],
pageActive: false,
shouldAnimate: true,
};
this.expandTimeout = undefined;
this.UIElements = [];
this.notificationTimeout = undefined;
this.longpress = 1300;
this.delay = undefined;
}
UNSAFE_componentWillMount() {
// this.getItems();
// this.setUIElements();
}
componentDidMount() {
if(this.expandTimeout !== undefined) {
clearTimeout(this.expandTimeout);
}
this.expandTimeout = setTimeout(()=> {
this.onExpand(true);
}, this.state.expandDelay*3);
key('up', this.keyScope, this.onMoveVertical.bind(this, 'UP'));
key('right', this.keyScope, this.onMoveHorizontal.bind(this, 'RIGHT'));
key('down', this.keyScope, this.onMoveVertical.bind(this, 'DOWN'));
key('left', this.keyScope, this.onMoveHorizontal.bind(this, 'LEFT'));
key('enter', this.keyScope, this.onEnter.bind(this));
key('m', this.keyScope, this.onToggleMenu.bind(this));
key('c', this.keyScope, this.triggerNotification.bind(this));
key.setScope(this.keyScope);
}
UNSAFE_componentWillReceiveProps(nextProps) {
const index = this.state.rails[this.state.indexY].children.length + 3;
this.setIndex(index, true);
}
setIndex(indexX, home) {
const offset = 585;
const transform = home
? ((((indexX - 2) * cardSizes.large) + cardSizes.small + cardSizes.music) - offset )
: ((((indexX - 1) * cardSizes.large) + cardSizes.small) - offset )
this.setState({
indexX,
transform,
});
}
triggerNotification() {
if(this.state.notifications.length > 0) {
// We already have a notification, we don't need another.
return;
}
const notifications = [
{
id:'incoming-call',
icon: '',
avatar: '/images/contacts/contact-prof.png',
primary:'Incoming call',
secondary: 'Aanya Singh',
action: 'Press OK to answer',
active: true
}
];
this.setState({
notifications: notifications
}, () => {
this.notificationTimeout = setTimeout(()=> {
this.notificationTimeout = undefined;
this.setState({
notifications:[]
});
}, 10 * 1000);
})
}
onEnter() {
const { history } = this.props;
const { active } = this.state;
const activeComponent = this[`rails-${this.className}-${this.state.indexY}`].props.children[this.state.indexX];
if(this.state.notifications.length > 0) {
history.push( {pathname: 'calling'} );
}
if (active && activeComponent.props.cardType === 'guide') {
history.push( {pathname: 'guide'} );
}
if(active && activeComponent.props.cardType === 'music') {
history.push( { pathname: "music-splash" });
}
}
onExpand(force) {
this.setState({
isExpanded: (force) ? force : !this.state.isExpanded,
expanding: true,
buddy:'EXPANDED'
}, (force)=> {
setTimeout(()=> {
this.setState({
expanding: false,
buddy:'FOCUS'
});
}, 250);
});
}
handleKeyUp = (direction) => {
key(direction.toLowerCase(), this.keyScope, this.onMoveHorizontal.bind(this, direction));
document.removeEventListener('keyup', this.handleKeyUp.bind(this, direction));
this.delay = undefined;
}
onMoveHorizontal = throttle((direction) => {
const targetX = this.state.indexX + ((direction === 'RIGHT') ? 1 : -1);
const activeRail = this[`rails-${this.className}-${this.state.indexY}`];
const actionLength = activeRail.props.children.length - 1;
let transform;
const cardTarget = direction === 'LEFT' ? targetX : targetX - 1;
const activeCard = activeRail.props.children[cardTarget];
const { cardType } = activeCard.props;
const baseLength = (actionLength + 1) / 3;
const exit = () => {
const { indexX } = this.state;
if ((direction === 'RIGHT' && indexX === (baseLength * 2)) || (direction === 'LEFT' && indexX === baseLength)) {
key.unbind(direction.toLowerCase(), this.keyScope, this.onMoveHorizontal.bind(this, direction));
setTimeout(() => {
this.handleKeyUp(direction);
}, 1500);
return false;
}
};
this.delay = setTimeout(exit, this.longpress);
if (direction === 'RIGHT' && targetX > (baseLength * 2)) {
if (this.state.indexY === 1) {
transform = this.state.transform - (((baseLength - 2) * cardSizes.large) + cardSizes.small + cardSizes.music);
} else {
transform = this.state.transform - ((baseLength * cardSizes.large) - (cardSizes.large - cardSizes.small));
}
this.setState({
indexX: baseLength + 1,
shouldAnimate: false,
transform: transform,
}, () => {
setTimeout(() => {
this.setState({
shouldAnimate: true,
transform: this.state.transform + cardSizes.small,
});
}, 0)
});
return;
} else if (direction === 'LEFT' && targetX < 2) {
const index = baseLength + 1;
if (this.state.indexY === 1) {
transform = ((index - 2) * (cardSizes.large) + cardSizes.small + cardSizes.music) - cardSizes.small - 90;
} else {
transform = ((index - 1) * (cardSizes.large) + cardSizes.small) - cardSizes.small - 90;
}
this.setState({
indexX: index,
shouldAnimate: false,
transform: transform,
}, () => {
setTimeout(() => {
this.setState({
shouldAnimate: true,
transform: this.state.transform - cardSizes.small,
});
}, 0)
});
return;
}
if (direction === 'RIGHT') {
if (cardType === 'guide') {
transform = this.state.transform + cardSizes.small;
} else if(cardType === 'music') {
transform = this.state.transform + cardSizes.music;
} else {
transform = this.state.transform + cardSizes.large;
}
} else {
if (cardType === 'guide') {
transform = this.state.transform - cardSizes.small;
} else if(cardType === 'music') {
transform = this.state.transform - cardSizes.music;
} else {
transform = this.state.transform - cardSizes.large;
}
}
if(this.state.indexY === 0 || this.state.indexY === 10 || this.state.indexY === 7 || targetX < 0 || targetX > actionLength) {
return;
} else {
this.setState({
indexX: targetX,
transform,
});
}
}, 100)
onMoveVertical(direction) {
const offset = (direction === 'DOWN') ? 1 : -1;
const targetY = this.state.indexY + offset;
if(targetY > this.state.rails.length-1 || targetY < 0) {
return;
}
else {
const isHome = targetY === 1;
const index = this.state.rails[targetY].children.length + (isHome ? 3 : 2);
this.setIndex(index, isHome);
this.setState({
indexY: targetY,
isExpanded: false,
buddy: direction,
}, ()=>{
if(this.expandTimeout !== undefined) {
clearTimeout(this.expandTimeout);
}
setTimeout(()=> {
this.setState({
buddy:'STATIC'
});
}, this.state.expandDelay / 2 );
this.expandTimeout = setTimeout(()=> {
this.onExpand(true);
}, this.state.expandDelay);
});
}
}
onToggleMenu() {
if(this.notificationTimeout !== undefined) {
clearTimeout(this.notificationTimeout);
this.notificationTimeout = undefined
}
this.setState({
active: !this.state.active,
pageActive: !this.state.pageActive,
notifications: []
}, () => {
if(!this.state.active) {
setTimeout(() => {
// LVNOTE: Loop and reset all
for (const name in this.refs) {
const component = this.refs[name];
if(component.onResetIndex) {
component.onResetIndex();
}
}
}, 250);
}
});
}
renderRails() {
const styleX = {
transform: `translate(-${this.state.transform}px, 0px)`,
transition: this.state.shouldAnimate ? 'transform 200ms' : '0ms',
};
const rails = this.state.rails.map((d,i) => {
let railTitle = d.title;
let railTheme = d.theme;
let railBecause = d.because;
let railIcon = d.icon;
const active = this.state.indexY === i;
const cards = d.children.map((item, j) => {
const sup = (j === 0)
? `${railBecause}`
: j === 2
? 'New shows added'
: '';
return (
<Card
id={`Square-${i}-${j}`}
title={item.title}
metadata={item.metadata}
image={`/images/artwork/${item.image}`}
key={`Square-${i}-${j}`}
type={'SquareCard'}
sup={sup}
pose={(active && this.state.indexX === (j + (i === 1 ? 2 : 1))) ? 'IF' : 'OOF'}
/>
);
});
//Push music card to first rail
//*** PLEASE NOTE - Issue with this card not becoming selected on home rail
if(i === 1) {
cards.unshift(
<MusicCard
railType="Home"
cardType="music"
id={i}
image='/images/music/Manto_SnehaKhanwalkar_1x1_01.png'
metadata="Playlist"
title="Manto"
type={'MusicCard'}
/>
);
}
cards.unshift(
<Card
cardType="guide"
icon={railIcon}
id={`Guide-1`}
theme={railTheme}
title={railTitle}
type={'SquareCard'}
/>
);
const children = [...cards, ...cards, ...cards];
const slides = [];
React.Children.forEach(children, (child, index) => {
const { cardType } = child.props;
const initialPose = cardType === 'music' ? 'OOF' : 'OOF';
slides.push(React.cloneElement(child, {
key: `card-${index}`,
pose: (active && this.state.indexX === index) ? 'IF' : 'OOF',
initialPose,
className: (active && this.state.indexX === index) ? 'active' : '',
}));
});
return (
<Item
pose={(active && this.state.isExpanded) ? 'open' : (this.state.isExpanded) ? 'hidden' : 'closed'}
active={active}
isExpanded={this.state.isExpanded}
currentIndex={this.state.indexY}
className={classNames('menuItem', { active })}
key={`pose-${i}`}
>
<div className="item-heading">
<p>{railTitle}</p>
</div>
{active &&
<Rail
className='rail'
pose={(active && this.state.isExpanded) ? 'open' : 'closed'}
ref={c => this[`rails-${this.className}-${i}`] = c}
style={styleX}
>
{slides}
</Rail>
}
</Item>
);
});
return rails;
}
render() {
const { menuItems } = this.state;
const yPos = 155 - (155 * this.state.indexY);
const styleY = { transform: `translate(0px, ${yPos}px)` };
const target = (this.state.isExpanded && this.state.expanding) ? 155 : 0;
return (
<div>
<div className={classNames(this.className, { active: true, 'page-active': this.state.pageActive, })}>
<TimeAndDate />
<div className='marker'></div>
<div className='buddy-holder'>
<Buddy
className='Buddy'
pose={this.state.buddy}
poseKey={target}
color={colors[0]}
target={target}
/>
</div>
<div className='menu' style={styleY}>
<PoseGroup selectedItemId={this.state.indexY} lastIndex={menuItems.length}>
{this.renderRails()}
</PoseGroup>
</div>
</div>
<NotificationCentre notifications={this.state.notifications} />
</div>
);
}
}
export default withRouter(MainMenu);
答案 0 :(得分:0)
您正在根据状态获取actionRail
<input id="fileUpload" name="fileUpload" type="file" accepts="image/*" class="fileFun file_uploader">
在更换路由器时,组件将丢失其状态,并且将无法找到要获取的组件。您可能要完全放弃使用组件内部的状态。