【问题标题】:Parent state not updating after function fired函数触发后父状态未更新
【发布时间】:2018-10-01 06:49:39
【问题描述】:

我已在父级中声明状态以确定用户是否已登录,如下所示

class App extends Component {
 constructor(props) {
  super(props)
  this.state = {
   isLoggedIn: false
  }
 }

 render() {
  <div>
   {
    (document.cookie && this.state.isLoggedIn) ? (
     <LoggedInHeader/>
    ) : <HomeHeader/>
   }

为了让用户登录,我向 api 发出 axios 请求,该请求又给了我一个存储在浏览器 cookie 中的令牌,下面的代码来自我的登录模式组件,我明确更新了将 axios 请求设置为 true 后的状态,控制台中的状态会按我的预期更新,但是当我检查布尔值是 true 还是 false 时,它​​处于原始状态。我知道“setState() 不会立即改变 this.state”,但似乎仍然无法改变状态。下面的登录表单组件是应用父级的子级。

loginSubmitHandler = (event) => {
event.preventDefault()

const user = "email=" + this.state.email + '&password=' + this.state.password

const instance = axios.create({
  baseURL: 'http://weburl',
  timeout: 1000,
  headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});

instance.post('/login', user)
  .then(res => {
    let d = new Date
    d.setDate(d.getDate() + 30)

    let expires = "expires=" + d

    document.cookie = "sessionname" + "=" + res.data.success.token + expires + ";path=/"
    console.log('changing state')
    this.setState({
      isLoggedIn: true
    }, () => {console.log('New state', this.state)})
  })
  .catch(err => {
    console.log(err, "There was an error")
})}

【问题讨论】:

  • 您正在 App 组件中存储isLoggedIn 状态。因此,登录后,您必须更新该状态。相反,您在子组件LoginForm 中设置状态。尝试通过将函数作为道具传递给 LoginForm 来更新父状态
  • 状态不传递给子组件吗?如果是这样,我需要更改它,以便在 App 组件中调用该函数并在那里设置状态,因为那是我控制布局的地方?
  • 不,每个组件都有自己的状态。你所做的是正确的。不要对 App 进行 api 调用。在 loginForm 本身中执行此操作并使用作为 prop 传递的函数更新父级中的状态。
  • 太棒了,感谢您对函数本身的过度思考,仍然掌握了道具和状态

标签: javascript reactjs cookies state axios


【解决方案1】:

您应该将函数从App 组件传递给表单组件,然后触发它。实际上,state 是每个组件的内部对象,所以它不能直接从另一个组件更新,除非使用回调函数。

例如:

class App extends Component {
    setAuthStatus = status => {
        this.setState({
            isLoggedIn: status,
        })
    }

    constructor(props) {
        super(props)
        this.state = {
            isLoggedIn: false,
        }
    }

    render() {
        return (
            <div>
                {
                    (document.cookie && this.state.isLoggedIn) ?
                        <LoggedInHeader/> : <HomeHeader/>
                }

                <LoginForm setAuthStatus={this.setAuthStatus}/>
            </div>
        )
    }
}

然后在你的表单中调用它

loginSubmitHandler = (event) => {
    event.preventDefault()

    const user = "email=" + this.state.email + '&password=' + this.state.password

    const instance = axios.create({
        baseURL: 'http://weburl',
        timeout: 1000,
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
    });

    instance.post('/login', user)
        .then(res => {
            let d = new Date
            d.setDate(d.getDate() + 30)

            let expires = "expires=" + d

            document.cookie = "sessionname" + "=" + res.data.success.token + expires + ";path=/"
            console.log('changing state')
            this.props.setAuthStatus(true)
        })
        .catch(err => {
            console.log(err, "There was an error")
        })
}

【讨论】:

  • 谢谢你,虽然我有一个用于登录和注册表单的容器组件,所以我需要在之后将它传递给这两个孩子(肯定是多虑了)
  • 您可以在容器中创建此函数并将其传递给多个组件(在您的情况下为表单)。
  • 我现在已经将函数传递给正确的组件,并且可以使用带有按钮的 onClick 处理程序对其进行更新,但可以使用 'this.props.setAuthSatus(true)' 在我的函数中调用它class 是从 React 扩展而来的类
  • 别担心,我已经想通了!
  • @EikHunter 很棒!
【解决方案2】:

您需要将父状态作为道具传递给子组件。

class Parent extends Component {
    constructor(props){
        super(props);
        this.state = {
            isLoggedIn: false
        }
    }
    render(){
        const {isLoggedIn} = this.state;
        return (
            <Child isLoggedIn={isLoggedIn} />
        )
    }
}

或者你可以在渲染内部实现逻辑。

render(){
    const {isLoggedIn} = this.state;
    if(isLoggedIn){
        return <LoggedInHeader />
    }
    return <HomeHeader />
}

【讨论】:

    猜你喜欢
    • 2020-08-19
    • 2022-01-08
    • 2020-11-06
    • 2019-07-04
    • 1970-01-01
    • 2016-09-18
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    相关资源
    最近更新 更多