如何在执行登录方法时从另一个组件正确更改组件的状态?

时间:2019-07-02 15:11:18

标签: reactjs

我有两个组件-一个登录表单组件,用于保存表单并处理登录逻辑,以及一个进度条,类似于SO的顶部。我希望能够在登录逻辑执行时显示进度条是否满满的情况,以便在发生情况时向用户显示加载的指示。我已经整理好样式,只需要了解如何正确触发功能即可。

我是React的新手,所以我的第一个想法是在handleFillerStateMax()中定义handleFillerStateMin()ProgressBarComponent来执行状态更改。当状态改变时,它基本上会改变进度条的宽度,所以一切正常。但是,当我的ProgressBarComponent组件Login逻辑执行时,如何从onSubmit调用函数?我已经评论了我的想法,但是它们显然不起作用。

ProgressBarComponent

class ProgressBarComponent extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            percentage: 0
        }
    }

    // the functions to change state
    handleFillerStateMax = () => {
        this.setState ({percentage: 100})
    }

    handleFillerStateMin = () => {
        this.setState ({percentage: 0})
    }

    render () {
        return (
            <div>
                <ProgressBar percentage={this.state.percentage}/>
            </div>
        )
    }
}

Login组件:

class SignInFormBase extends Component {
    constructor(props) {
        super(props);

        this.state = {...INITIAL_STATE};
    }

    onSubmit = event => {

        const {email, password} = this.state;

        // ProgressBarComponent.handleFillerMax()????

        this.props.firebase
            .doSignInWithEmailAndPass(email,password)
            .then(()=> {
                this.setState({...INITIAL_STATE});
                this.props.history.push('/');

                //ProgressBarComponent.handleFillerMin()????

            })
            .catch(error => {
                this.setState({error});
            })
        event.preventDefault();
}

2 个答案:

答案 0 :(得分:1)

重述您在做什么。不是“设置进度条的进度”,而是“修改应用程序状态,以便进度条将使用新数据重新呈现。”

  1. 保持SignInFormBaseProgressBarComponent的父级状态下的当前进度,并将其作为prop传递给ProgressBarComponent,以便仅显示所告知的内容。除非ProgressBar中省略了一些内部逻辑来处理自己的进度更新;在那吗?
  2. 将回调传递给SignInFormBase,当它有新的信息要报告时可以调用该回调:即,将ProgressBarComponent.handleFillerMax()替换为this.props.reportProgress(100)或类似的东西。回调应为setState({progress: value})

现在,当SignInFormBase调用reportProgress回调时,它将在父组件中设置状态。此状态作为prop传递给ProgressBarComponent,因此更改后的事实将导致进度条重新呈现。

要求的#2示例,类似于以下未经测试的代码:

class App extends Component {
  handleProgressUpdate(progress) {
    this.setState({progress: progress});
  }

  render() {
    return (
      <MyRootElement>
        <ProgressBar progress={this.state.progress} />
        <LoginForm onProgressUpudate={(progress) => this.handleProgressUpdate(progress)} />
      </MyRootElemen>
    )
  }
}

只要this.props.onProgressUpdate(value)从具有LoginForm的新信息开始就应该更改值,就可以对其进行简单调用。

答案 1 :(得分:1)

从根本上讲,这是一种适合的结构(为简洁起见,使用useState,但如果愿意,它当然可以是基于类的有状态组件):

const App = ()=> {
    const [isLoggingIn, setIsLoggingIn] = useState(false)
    const handleOnLoginStart = () => {
       setIsLoggingIn(true)
    }
    const handleOnLoginSuccess = () => {
       setIsLoggingIn(false)
    }
    <div>
       <ProgressBar percentage={isLoggingIn?0:100}/>
       <LoginForm onLoginStart={handleOnLogin} onLoginSuccess={handleOnLoginSuccess}/>
    </div>

}

在您的LoginForm中,您将:

onSubmit = event => {

    const {email, password} = this.state;

    this.props.onLoginStart() // <-- call the callback

    this.props.firebase
        .doSignInWithEmailAndPass(email,password)
        .then(()=> {
            this.setState({...INITIAL_STATE});
            this.props.history.push('/');

            this.props.onLoginSuccess() // <-- call the callback


        })
        .catch(error => {
            this.setState({error});
        })
    event.preventDefault();
 }