React 路由器本机动画在动画开始前闪烁
React router native animation blinks before animation starts
我正在开发一个 React Native 应用程序并使用 React Router Native v4,并且我正在尝试开发动画部分,正如文档所建议的那样,首先我确保一切都在没有动画或过渡的情况下工作。
我已经迭代了实现,这是我目前为止得到的:
我的主要组件呈现以下内容:
// app.js:render
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
my routes.js 呈现以下内容(注意传递给 Switch 的 location 属性,以防止它在父组件之前更新其子组件):
// routes.js render
<ViewTransition pathname={location.pathname}>
<Switch location={location}>
<Route exact path={uri.views.main} component={Dashboard} />
<Route path={uri.views.login} component={Login} />
<Route path={uri.views.register} component={Register} />
</Switch>
</ViewTransition>
和处理动画的 ViewTransition,现在它只是 fadesin/out 旧视图和新视图:
// view-transition.js
@withRouter
export default class ViewTransition extends Component {
static propTypes = {
children: PropTypes.node,
location: PropTypes.object.isRequired,
};
state = {
prevChildren: null,
opacity: new Animated.Value(1)
};
componentWillUpdate(nextProps) {
if (nextProps.location !== this.props.location) {
this.setState({ prevChildren: this.props.children }, this.animateFadeIn);
}
}
animateFadeIn = () => {
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 150
}).start(this.animateFadeOut);
};
animateFadeOut = () => {
this.setState({ prevChildren: null }, () => {
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 400
}).start();
});
};
render() {
const { children } = this.props;
const { prevChildren, opacity } = this.state;
return (
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
opacity,
position: "absolute"
}}
>
{prevChildren || children}
</Animated.View>
);
}
}
上面的代码有效,我可以看到旧视图淡出和新视图淡入,但我有一个问题,当它开始淡出时,组件以某种方式再次重新安装,我可以看到在动画开始了,我想知道我的代码有什么问题。
我可以修复上面的代码,碰巧 React 组件生命周期中的方法 componentWillUpdate 已经将 nextProps 传递给 children,同时我的组件设置了新状态旧的 children,Switch 正在准备新的渲染,这会产生旧的 oldChildren 的卸载和新的 children 的安装,当我的组件最终完成设置状态时,旧的 children 已经卸载,必须重新安装。
上面的故事是"I can see a blink when my animation starts"的长篇大论,解决方法恰好很简单,我不再检查componentWillUpdate
中的内容而是在componentWillReceiveProps
中检查内容,因为新props 将在其 children 之前传递给 parent 组件,它让我有足够的时间来捕获当前的 children,将它们分配给状态,在 Switch 卸载它们之前进行渲染并将它们保留在查看淡出,不再闪烁。
我的决赛view-transition.js:
// view-transition.js
export default class ViewTransition extends Component {
static propTypes = {
children: PropTypes.node,
location: PropTypes.object.isRequired,
};
state = {
prevChildren: null,
opacity: new Animated.Value(1)
};
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
this.setState({ prevChildren: this.props.children }, this.animateFadeIn);
}
}
animateFadeIn = () => {
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 150
}).start(this.animateFadeOut);
};
animateFadeOut = () => {
this.setState({ prevChildren: null }, () => {
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 400
}).start();
});
};
render() {
const { children } = this.props;
const { prevChildren, opacity } = this.state;
return (
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
opacity,
position: "absolute"
}}
>
{prevChildren || children}
</Animated.View>
);
}
}
嗯..我知道有点晚了,也许你可以试试react-router-native-animate-stack
它是 react-router-native
的子组件。但它是可动画的并提供堆栈功能。它的灵感来自switch
组件,如果你知道switch
,你就会知道如何使用这个包。
Default behaviour
Customization
我写了一个 AnimatedSwitch 组件在 React Native 中工作。
有一个短暂的状态正在更新并且它会闪烁,但我用这段代码修复了这个问题:
// Need to render the previous route for the time between not animating and animating
if (needsAnimation && !animating) {
const tempPreviousRoute = getPreviousRoute(
exact,
previousLocation,
previousChildren,
);
if (tempPreviousRoute) {
const prevRouteComp = renderPreviousRoute(tempPreviousRoute);
return prevRouteComp;
} else {
return null;
}
}
完整代码在这里。
https://javascriptrambling.blogspot.com/2020/07/react-router-native-animatedswitch.html
我正在开发一个 React Native 应用程序并使用 React Router Native v4,并且我正在尝试开发动画部分,正如文档所建议的那样,首先我确保一切都在没有动画或过渡的情况下工作。
我已经迭代了实现,这是我目前为止得到的:
我的主要组件呈现以下内容:
// app.js:render
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
my routes.js 呈现以下内容(注意传递给 Switch 的 location 属性,以防止它在父组件之前更新其子组件):
// routes.js render
<ViewTransition pathname={location.pathname}>
<Switch location={location}>
<Route exact path={uri.views.main} component={Dashboard} />
<Route path={uri.views.login} component={Login} />
<Route path={uri.views.register} component={Register} />
</Switch>
</ViewTransition>
和处理动画的 ViewTransition,现在它只是 fadesin/out 旧视图和新视图:
// view-transition.js
@withRouter
export default class ViewTransition extends Component {
static propTypes = {
children: PropTypes.node,
location: PropTypes.object.isRequired,
};
state = {
prevChildren: null,
opacity: new Animated.Value(1)
};
componentWillUpdate(nextProps) {
if (nextProps.location !== this.props.location) {
this.setState({ prevChildren: this.props.children }, this.animateFadeIn);
}
}
animateFadeIn = () => {
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 150
}).start(this.animateFadeOut);
};
animateFadeOut = () => {
this.setState({ prevChildren: null }, () => {
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 400
}).start();
});
};
render() {
const { children } = this.props;
const { prevChildren, opacity } = this.state;
return (
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
opacity,
position: "absolute"
}}
>
{prevChildren || children}
</Animated.View>
);
}
}
上面的代码有效,我可以看到旧视图淡出和新视图淡入,但我有一个问题,当它开始淡出时,组件以某种方式再次重新安装,我可以看到在动画开始了,我想知道我的代码有什么问题。
我可以修复上面的代码,碰巧 React 组件生命周期中的方法 componentWillUpdate 已经将 nextProps 传递给 children,同时我的组件设置了新状态旧的 children,Switch 正在准备新的渲染,这会产生旧的 oldChildren 的卸载和新的 children 的安装,当我的组件最终完成设置状态时,旧的 children 已经卸载,必须重新安装。
上面的故事是"I can see a blink when my animation starts"的长篇大论,解决方法恰好很简单,我不再检查componentWillUpdate
中的内容而是在componentWillReceiveProps
中检查内容,因为新props 将在其 children 之前传递给 parent 组件,它让我有足够的时间来捕获当前的 children,将它们分配给状态,在 Switch 卸载它们之前进行渲染并将它们保留在查看淡出,不再闪烁。
我的决赛view-transition.js:
// view-transition.js
export default class ViewTransition extends Component {
static propTypes = {
children: PropTypes.node,
location: PropTypes.object.isRequired,
};
state = {
prevChildren: null,
opacity: new Animated.Value(1)
};
componentWillReceiveProps(nextProps) {
if (nextProps.location !== this.props.location) {
this.setState({ prevChildren: this.props.children }, this.animateFadeIn);
}
}
animateFadeIn = () => {
Animated.timing(this.state.opacity, {
toValue: 0,
duration: 150
}).start(this.animateFadeOut);
};
animateFadeOut = () => {
this.setState({ prevChildren: null }, () => {
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 400
}).start();
});
};
render() {
const { children } = this.props;
const { prevChildren, opacity } = this.state;
return (
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
opacity,
position: "absolute"
}}
>
{prevChildren || children}
</Animated.View>
);
}
}
嗯..我知道有点晚了,也许你可以试试react-router-native-animate-stack
它是 react-router-native
的子组件。但它是可动画的并提供堆栈功能。它的灵感来自switch
组件,如果你知道switch
,你就会知道如何使用这个包。
Default behaviour
Customization
我写了一个 AnimatedSwitch 组件在 React Native 中工作。
有一个短暂的状态正在更新并且它会闪烁,但我用这段代码修复了这个问题:
// Need to render the previous route for the time between not animating and animating
if (needsAnimation && !animating) {
const tempPreviousRoute = getPreviousRoute(
exact,
previousLocation,
previousChildren,
);
if (tempPreviousRoute) {
const prevRouteComp = renderPreviousRoute(tempPreviousRoute);
return prevRouteComp;
} else {
return null;
}
}
完整代码在这里。
https://javascriptrambling.blogspot.com/2020/07/react-router-native-animatedswitch.html