我一直在努力克服兄弟组件(没有父子关系的组件)之间的组件行为的概念。
我有一个App组件,可以呈现标题和内容组件。标题包含一个允许用户导航回来的按钮(在本例中不是真实的)。现在我希望内容组件覆盖后退按钮的行为,例如,如果用户正在编辑表单,我想弹出一个模态。
我想这样做的原因是因为我想(可选)控制内容组件本身内的导航。
我找到了这个(参见代码片段)解决方案,但我觉得这不是解决这个问题的正确方法。我想就如何处理这种情况提出一些建议。
一些附注:
我实际上正在构建一个反应原生的应用程序,但为了吸引更多人,我已将其简化为反应示例。我正在使用NavigatorExperimental进行导航。
我使用的是redux / redux-form
感谢任何帮助。
class NavigationHeader extends React.Component {
render() {
return (
<span onClick={this.props.goBack}>Go back!</span>
);
}
}
class Content extends React.Component {
componentDidMount() {
this.props.setBackButtonBehaviour(() => console.log("BackButton overridden from Content"));
}
componentWillUnmount() {
this.props.resetBackButtonBehaviour();
}
render() {
return (<div style={{background: "red"}}>Content</div>);
}
}
class Navigator extends React.Component {
constructor(props) {
super(props);
this.state = {
overrideHeaderBackButtonBehaviour: null
}
}
setBackButtonBehaviour(func) {
this.setState({overrideHeaderBackButtonBehaviour: func});
}
resetBackButtonBehaviour() {
this.setState({overrideHeaderBackButtonBehaviour: null});
}
defaultBackButtonBehaviour() {
console.log("Default back-button behaviour");
}
render() {
return (
<div>
<NavigationHeader goBack={this.state.overrideHeaderBackButtonBehaviour || this.defaultBackButtonBehaviour} />
<Content
setBackButtonBehaviour={this.setBackButtonBehaviour.bind(this)}
resetBackButtonBehaviour={this.resetBackButtonBehaviour.bind(this)}
/>
</div>
);
}
}
ReactDOM.render(<Navigator />, 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">
</div>
答案 0 :(得分:0)
您可以尝试这样的事情:
import actions from './actions';
@connect(
// map state to props
(state, props) => ({
canNavigate: state.navigation.canNavigate,
}),
// map dispatch to props
{
goBack: actions.goBack,
showNavigationAlert: actions.showNavigationAlert,
}
)
class Header extends React.Component {
render() {
return (
{/* if 'canNavigate' flag is false and user tries to navigate, then show alert */}
<span
onClick={this.props.canNavigate ? this.props.goBack : this.props.showNavigationAlert}
>
Go back!
</span>
);
}
}
import actions from './actions';
@connect(
// map state to props
(state, props) => ({
navigationAlert: state.navigation.navigationAlert,
}),
// map dispatch to props
{
toggleNavigation: actions.toggleNavigation,
}
)
class Content extends React.Component {
render() {
return (
<div>
{/*
Show modal if 'navigationAlert' flag is true;
From the modal, if user choose to leave page then call toggleNavigation.
You may call the corresponding navigation function after this (eg: goBack)
*/}
{this.props.navigationAlert && <Modal toggleNavigation={this.props.toggleNavigation} />}
{/* eg: disable navigation when clicked inside the div */}
<form onClick={this.props.toggleNavigation}>
Content click!
</form>
</div>
);
}
}
class App extends React.Component {
render() {
return (
<div>
<Header />
<Content />
</div>
);
}
}
const initialState = {
canNavigate: true,
navigationAlert: false,
};
export function navigationReducer(state = initialState, action = {}) {
let newState = {};
switch (action.type) {
case TOGGLE_NAVIGATION:
return { ...state, canNavigate: !state.canNavigate };
case TOGGLE_NAVIGATION_ALERT:
return { ...state, navigationAlert: !state.navigationAlert };
default:
return state;
}
}
export function toggleNavigation(gdsSession) {
return { type: TOGGLE_NAVIGATION };
}
export function toggleNavigationAlert(gdsSession) {
return { type: TOGGLE_NAVIGATION_ALERT };
}
// ... other actions
并渲染成DOM。
ReactDOM.render(<App />, document.getElementById("app"));