如何仅在我的组件第一次呈现时更新我的​​菜单状态?

How can I update the state of my menu only on the first time my component renders?

我有一个使用参数调用的应用程序。现在,我的菜单总是加载到默认的 MainMenu。我希望能够将状态传递给 Menu.js 并从打开的不同菜单开始,而不是默认的 MainMenu。

我认为 componentWillMount() 可以让我将我的状态设置为我选择的菜单状态,但无论出于何种原因,它都没有更新呈现的内容。当我调用它时,this.state.Selected 成为我想要呈现的正确菜单名称...但它实际上并没有呈现 - 它最终呈现默认菜单。

所以我必须在 componentWillMount() 之后调用其他东西才能让它真正呈现?

Landing.js - 调用 Menu.js。我想先渲染菜单 'FileOptions'。但是,它当前正在呈现 MainMenu。

import React, { Component } from 'react'
import sass from '../scss/application.scss'
import PropTypes from 'prop-types'
import Header from './Header'
import Menu from './Menu'
import HelpFile from './HelpFile'



class Landing extends Component {
    constructor(props) {
         super(props);
         this.state = { 
             helpFileName: 'Mainmenu',
             menuName: 'FileOptions',
         }
       }

    handleHelpChange(helpFileName) {
        this.setState( {helpFileName} );
    }

    handleMenuClick(menuName) {
        this.setState( {menuName} );
    }

    componentWillMount() {
        let hlpString = require('electron').remote.getGlobal('sharedObject').hlpOne;
        if (hlpString != null && hlpString != '.')
        {
            this.setState({
                helpFileName: hlpString
            });ss
        }
    }

    render() {  

        return (
            <div>
                <div>
                    <Header />
                </div>
                <br /><br />
                <div className="mainMenuDiv">
                    <Menu handleHelpChange={this.handleHelpChange.bind(this)} menuName={this.state.menuName}/>
                </div>
                <div className="mainContainerDiv">
                    <HelpFile name={this.state.helpFileName}/>
                </div>
            </div>

        )
    }
}


export default Landing;

Menu.js

import React, { Component } from 'react'
import sass from '../scss/application.scss'
import PropTypes from 'prop-types'



class Menu extends Component {
    constructor(props) {
         super(props);
         this.state = { 
             Selected: props.menuName,      // reads FileOptions, but still renders MainMenu
             name: ''
         }
       }

    handleChange(name) {
        this.setState({
            name: name
        });
    }

    handleClick(e, num) {
        this.setState({
            name: num
          }, () => {
            let helpFileName = num;
            helpFileName = helpFileName.toLowerCase().trim();
            //Cap the first letter in the name and add the rest of the name 
            helpFileName = helpFileName.charAt(0).toUpperCase() + helpFileName.substr(1);
            this.props.handleHelpChange(helpFileName);
          });
      }

     handleMenuClick(e, num, opt) {
        this.setState({
            name: num,
            Selected: opt
          }, () => {
            let helpFileName = num;
            helpFileName = helpFileName.toLowerCase().trim();
            //Cap the first letter in the name and add the rest of the name 
            helpFileName = helpFileName.charAt(0).toUpperCase() + helpFileName.substr(1);
            this.props.handleHelpChange(helpFileName);
          });
      }

    render() {
        const MainMenu = () => (
            <div>
                <button 
                    label="File Options"
                    //onClick={() => this.setState({ Selected: FileOptions })} 
                    onClick={(e) => this.handleMenuClick(e, 'Fileopt', FileOptions)}
                    className="aMenuButton"
                >FILE OPTIONS</button>
                <button 
                    label="Setup Options"
                    onClick={(e) => this.handleMenuClick(e, 'Setupopt', SetUpOptions)}
                    className="aMenuButton"
                >SETUP OPTIONS</button>
                <button 
                    label="Lumber Options"
                    onClick={(e) => this.handleMenuClick(e, 'Lumberopt', MoreOptions)}
                    className="aMenuButton"
                >MORE OPTIONS</button>
                <button 
                    label="Main Menu"
                    onClick={(e) => this.handleClick(e, 'Mainmenu')} 
                    className="aPrevButton"
                >MAIN MENU</button>
            </div>
        );

        const FileOptions = () => (
            <div>
                <button 
                    label="Option One"
                    onClick={(e) => this.handleClick(e, 'Option One')}
                    className="aMenuButton"
                >Option One</button>
               <button 
                    label="Option Two"
                    onClick={(e) => this.handleClick(e, 'Option Two')}
                    className="aMenuButton"
                >Option Two</button>
                <button 
                    label="Option Three"
                    onClick={(e) => this.handleClick(e, 'Option Three')}
                    className="aMenuButton"
                >Option Three</button>
                <button 
                    label="Option Four"
                    onClick={(e) => this.handleClick(e, 'Option Four')}
                    className="aMenuButton"
                >Option Four</button>
                <button 
                    label="Previous Menu"
                    onClick={() => this.setState({ Selected: MainMenu })} 
                    className="aPrevButton"
                >PREVIOUS MENU</button>
            </div>
        );

        const SetUpOptions = () => (
            <div>
                <button 
                    label="Option One"
                    onClick={(e) => this.handleClick(e, 'Option One')}
                    className="aMenuButton"
                >Option One</button>
               <button 
                    label="Option Two"
                    onClick={(e) => this.handleClick(e, 'Option Two')}
                    className="aMenuButton"
                >Option Two</button>
                <button 
                    label="Option Three"
                    onClick={(e) => this.handleClick(e, 'Option Three')}
                    className="aMenuButton"
                >Option Three</button>
                <button 
                    label="Previous Menu"
                    onClick={() => this.setState({ Selected: MainMenu })} 
                    className="aPrevButton"
                >PREVIOUS MENU</button>
            </div>
        );

        const MoreOptions = () => (
            <div>
                <button 
                    label="Option One"
                    onClick={(e) => this.handleClick(e, 'Option One')}
                    className="aMenuButton"
                >Option One</button>
               <button 
                    label="Option Two"
                    onClick={(e) => this.handleClick(e, 'Option Two')}
                    className="aMenuButton"
                >Option Two</button>
                <button 
                    label="Option Three"
                    onClick={(e) => this.handleClick(e, 'Option Three')}
                    className="aMenuButton"
                >Option Three</button>
                <button 
                    label="Option Four"
                    onClick={(e) => this.handleClick(e, 'Option Four')}
                    className="aMenuButton"
                >Option Four</button>
                <button 
                    label="Previous Menu"
                    onClick={() => this.setState({ Selected: MainMenu })} 
                    className="aPrevButton"
                >PREVIOUS MENU</button>
            </div>
        );

        const { Selected } = this.state;

        return (
            <div>   
                <div className="menuButtons">
                    {Selected === 'MainMenu' ? <MainMenu /> : <Selected /> }
                </div>
            </div>
        )
    }
}

Menu.propTypes = {  
    handleHelpChange: PropTypes.func,
    name: PropTypes.string,
    menuName: PropTypes.string
}


export default Menu;

来自react docs for componentWillMount,

componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state synchronously in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method. This is the only lifecycle hook called on server rendering. Generally, we recommend using the constructor() instead.

更新 1

在构造函数中设置您选择的菜单名称并从 componentWillMount 中删除 setState。

更新 2

@Yiou 注意到 <Selected /> 不是一个组件。

class Menu extends Component {
    constructor(props) {
      super(props);
      this.state = { 
        Selected: props.menuName || '',
        name: ''
      }
    }

  // ....

  render() {

    // after you created all your menu constant implement a switch to select
    // which menu is going to render
    const { Selected } = this.state;
    let SelectedMenu;
    switch(Selected) {
      case 'MainMenu':
        SelectedMenu = MainMenu;
        break;
      case 'FileOptions':
        SelectedMenu = FileOptions;
        break;
      default:
        SelectedMenu = MainMenu;
        break;
    }

    return (
        <div>   
            <div className="menuButtons">
                {SelectedMenu()}
            </div>
        </div>
    )
  }    
}