setState不是更新状态

问题描述 投票:0回答:1

我试图在用户登录时渲染App.js中的组件,但是当我在App.js中设置状态(以渲染组件)时,状态不会改变

首先,我将用户名和密码从login.js发送到App.js:

  loginSubmit= (e) => {
    e.preventDefault()

      if(this.state.username === "") {
        this.showValidationErr("username", "Username cannot be empty")
      } if (this.state.password === "") {
        this.showValidationErr("password", "Password cannot be empty")
      }


    const username = this.state.username
    this.props.login(username)

这在App.js中呈现:

render() {
    return (
      <div className="container">
        <h1>Lightning Talks!</h1>
          <Login login={this.login}/>
            {this.state.loggedIn ? <lightningTalkRender/> : null}
          <h3 className="form-header"> Submit your talk</h3>
        <Form postInApp={this.postInApp}/>
      </div>
    )
  }

它应该调用App.js中的登录功能(之所以完成,是因为我console.log(username)并收到了它:]]

 login = (username) => {
    console.log('username', username)
    console.log('username state', this.state.username)

    this.setState({
      loggedIn: true,
      username: username
    });
    console.log('username', username) // username typed in is logged
    console.log('username state', this.state.username) //username in state is empty

    console.log('logged in state', this.state.loggedIn) // loggedIn is still false
  }

完成后,loginIn应该变为true,这将在App.js中呈现lightningTalkComponent(另请参见上文):

{this.state.loggedIn ? <lightningTalkRender/> : null}

App.js的初始状态为:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      lightningTalks: [],
      username: "",
      loggedIn: false
    };
  }

为什么状态不更新?

完整代码在这里:

import React from 'react';
import LightningTalk from './components/lightning-talk-component.js';
import Form from './components/form.js';
import Login from './components/login.js';
import './App.css'


// initialized state of App to hold an empty lightningTalks compoennt. componentDidMount sets its state depends
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      lightningTalks: [],
      username: "",
      loggedIn: false
    };
  }

// componentDidMount is called and sets the state of the lightningTalks array in constructor(props)
  componentDidMount = () => {
    fetch("http://localhost:4000/talks.json")
    .then(response => response.json())
    .then((data) => {
      // sorts the data when component mounts from largest to smallest votes
      data.sort((a, b) => b.votes - a.votes)
      this.setState((state) => {
        return {
          lightningTalks: data
        };
      });
    });
  }

// sends a post request to the API
  postInApp = (titleDescription) => {
    const talk = {}
    talk.title = titleDescription.title
    talk.description = titleDescription.description
    talk.votes = 0

      fetch("http://localhost:4000/talks", {
        headers: {
          "Content-Type": "application/json"
        },
        method: "POST",
        body: JSON.stringify({ "talk": talk })
        })
      .then(response => response.json())
      .then((data) => {
         console.log(data);
      });
  }

  login = (username) => {
    console.log('username', username)
    console.log('username state', this.state.username)

    this.setState({
      loggedIn: true,
      username: username
    });
    console.log('username', username)
    console.log('username state', this.state.username)

    console.log('logged in state', this.state.loggedIn)
  }

// increments/decrements the votes in an object of lightningTalks
  incrementInApp = (id) => {
    // creates a new array based off current state of lightningTalks
    const nextLightningTalks = this.state.lightningTalks.map((currentLightningTalk) => {
      // if the id in the parameters equals the id of the current objects ID then place back into the array
      if (currentLightningTalk.id !== id) {
        return currentLightningTalk
      }
      // whatever remains (the one whose ID does match), += 1 votes of that object
        const nextLightningTalk = {...currentLightningTalk, votes: currentLightningTalk.votes + 1,
        };
    return nextLightningTalk
    })
    // sorts when number of votes increases
    nextLightningTalks.sort((a, b) => b.votes - a.votes)
// set new state of lightningTalks to equal the result of the new array above (the .map)
  this.setState({lightningTalks: nextLightningTalks})
  }

  decrementInApp = (id) => {
    const nextLightningTalks = this.state.lightningTalks.map((currentLightningTalk) => {
      if (currentLightningTalk.id !== id) {
        return currentLightningTalk
      }
        const nextLightningTalk = {...currentLightningTalk, votes: currentLightningTalk.votes - 1,
        };
    return nextLightningTalk
    })
     // sorts when number of votes decreases
    nextLightningTalks.sort((a, b) => b.votes - a.votes)

  this.setState({lightningTalks: nextLightningTalks})
  }

  lightningTalkRender(props) {
    return <div className="talks">
      {this.state.lightningTalks.votes}
        {this.state.lightningTalks.map((talk) => {
          return <LightningTalk lightningTalk={talk} incrementInApp={this.incrementInApp} decrementInApp={this.decrementInApp}/>
                })}
            </div>
  }

  // now the state of lightning talks depends on what is on the API. Below there is a loop(.map) which is set by componentDidMount
  render() {
    return (
      <div className="container">
        <h1>Lightning Talks!</h1>
          <Login login={this.login}/>
            {this.state.loggedIn ? <lightningTalkRender/> : null}
          <h3 className="form-header"> Submit your talk</h3>
        <Form postInApp={this.postInApp}/>
      </div>
    )
  }
}

export default App;


import React from "react"
import './login.css';

class Login extends React.Component {
  constructor(props) {
    super(props);
    this.loginSubmit = this.loginSubmit.bind(this)
      this.state = {
        username: '',
        password: '',
        errors: [],
        pwdStrength: null
      }
  }

  showValidationErr (e, msg) {
    this.setState((prevState) => ( { errors: [...prevState.errors, { e, msg }] } ));
  }

  clearValidationErr (e) {
    this.setState((prevState) => {
      let newArr = [];
      for(let err of prevState.errors) {
        if(e !== err.e) {
          newArr.push(err);
        }
      }
      return {errors: newArr};
    })
  }

   onUsernameChange= (e) => {
    this.setState({ username: e.target.value })
    this.clearValidationErr("username");
   }

   onPasswordChange= (e) => {
    this.setState({ password: e.target.value })
    this.clearValidationErr("password");
    // set state of password strength based on length. Render these as CSS below
    if (e.target.value.length <= 8) {
      this.setState({ pwdStrength: "pwd-weak"})
    } if (e.target.value.length > 8) {
      this.setState({ pwdStrength: "pwd-medium" })
    } if (e.target.value.length > 12) {
      this.setState({ pwdStrength: "pwd-strong" })
    }
  }

 // on submit, time is logged (new Date) and state of title and description is changed
   loginSubmit= (e) => {
    e.preventDefault()

      if(this.state.username === "") {
        this.showValidationErr("username", "Username cannot be empty")
      } if (this.state.password === "") {
        this.showValidationErr("password", "Password cannot be empty")
      }


    const username = this.state.username
    this.props.login(username)
    // call onSubmit in LightningTalk so that new talk is added from form

    // this.props.postInApp(usernamePassword)
   }
   render() {

    let usernameErr = null;
    let passwordErr = null;

    for(let err of this.state.errors) {
      if(err.e === "username") {
        usernameErr = err.msg
      } if (err.e === "password") {
        passwordErr = err.msg
      }
    }

    return (
      <form className="form-container">
        <label>
        <p className="form-title">Username:</p>
          <input className="input-username"
          placeholder="enter your username"
          value={this.state.username}
          onChange={this.onUsernameChange}
          />
          <small className = "danger-error"> { usernameErr ? usernameErr : "" }</small>
        </label>
        <br />
        <label>
        <p className="form-description">Password:</p>
          <input className="input-password"
          placeholder="enter your password"
          value={this.state.password}
          onChange={this.onPasswordChange}
          type="password"
          />
          <small className="danger-error"> { passwordErr ? passwordErr : "" }</small>
          {this.state.password && <div className="password-state">
            <div
              className={"pwd " + (this.state.pwdStrength)}></div>
          </div>}
        {/*when the button is clicked, call the loginSubmit function above. E (event) is passed into loginSubmit function (above)*/}
        </label>
        <br />
        <button onClick={e => this.loginSubmit(e)}>Login</button>
      </form>
      );
    }
}

export default Login;

我试图在用户登录时渲染App.js中的组件,但是当我在App.js中设置状态(以渲染组件)时,状态不会更改。首先,我从..发送用户名和密码。 。

reactjs
1个回答
0
投票

[setState是异步的。如果要在设置后查看其状态,请使用回调函数

© www.soinside.com 2019 - 2024. All rights reserved.