提升状态并更新它

时间:2019-05-14 17:01:24

标签: reactjs

我有一个关于提升状态的问题,我知道他是这里的一个常见问题,但我希望有人会设法帮助我理解。

问题:我有一个由表单组件组成的登录组件,我在其中进行提取调用以执行登录。我想保留从fetch调用中获取的令牌并将其保存在App组件中,以便可以使用此令牌并将其传递给其他页面/组件。

那么,首先要从我的App.js /父组件中的代码开始?

在这里,我管理我的路线,这也是我要存储其状态的她。 我将令牌从此状态传递到Login组件,如呈现Login组件的Route所示。

从我读到的内容来看,道具不是可变的,所以这实际上不符合我的想法吗?我做了handleToken函数,但我会返回。

export default class App extends Component {
state = {
    token: "",
    regNo: "",
};

handleToken = (token) => {
    this.setState({ token: token})
}

render() {
    console.log(this.state.token);
    return (
        <Router >
            <div>
                <Header />
                <Navbar isLoggedIn={this.state.token} />
                <Switch>
                    <Route exact path="/" render={() => <Home />} />
                    <Route path="/profile" render={() => <Profile userToken={this.state.token} />} />
                    <Route path="/login" render={() => <Login userToken={this.state.token} />} />
                    <Route path="/register" render={() => <Register />} />
                    <Route path="/carpage" render={() => <CarPage regNo={this.state.regNo} />} />
                    <Route path="/find-rental" render={() => <FindRental regNo={this.state.regNo} setRegno={this.setRegno}/>} />
                    <Route path="/rent-out-car" render={() => <RentOutCar />} />
                    <Route component={NoMatch} />
                </Switch>
            </div>
        </Router >
    );
};

现在,我们移至“登录”组件。该组件由组成登录页面的多个其他组件组成。其中之一是FormContainer,在其中进行登录的获取调用。

const Login = (props) => (
  <Container fluid={true}>
    <BrandRow>
    </BrandRow>
    <FormRow>
      <FormContainer /* userToken={this.props.userToken} */ />
    </FormRow>
  </Container>
);

export default Login;

(不知道为什么它不能作为代码示例正确呈现,所以它进入了代码片段)

因此,如您在此登录组件中所见,我拥有FormContainer,它是所有操作发生的地方。

让我告诉你:

class FormContainer extends Component {
  state = {
    userName: '',
    password: '',
  };

  handleChange = event => {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.setState({ [name]: value });
  }

  handleSubmit = event => {
    event.preventDefault();
    const credentials = { username: this.state.userName, password: this.state.password };
    this.login(credentials);
  }

  login = credentials => {
    const url = "https://fenonline.dk/SYS_Backend/api/login";
    const postHeader = {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(credentials)
    };
    fetch(url, postHeader).then(res => {
      if (!res.ok) { throw Error(res.status + ": " + res.statusText + " | Wrong username or password!"); }
      return res.json();
    }).then(data => {
      this.props.userToken = data.token;
      alert("You have succesfully logged in!" + data.token);
      this.props.history.push('/profile')
    }).catch(error => alert(error));
  }

  render() {
    const { userName, password } = this.state;
    return (
      <Container>
        <Form onSubmit={this.handleSubmit}>
          <Title>Sign In</Title>
          <Input
            type="text"
            name="userName"
            value={userName}
            onChange={this.handleChange}
            placeholder="Username.."
          />
          <Input
            type="password"
            name="password"
            value={password}
            onChange={this.handleChange}
            placeholder="Password.."
          />
          <Button type="submit">Sign In</Button>
          <Button onClick={() => this.props.history.push('/register')}>Register</Button>
        </Form>
        <Text>Rental service created by users for users.</Text>
      </Container>
    );
  }
}

export default withRouter(FormContainer);

您要在这里查看的是登录功能,我在其中创建了fetch调用,这是我在其中获取要保存到其提升状态的令牌的地方。现在,我尝试通过说this.props.userToken = data.token进行设置;但是如果道具是永恒的,我该怎么做?

1 个答案:

答案 0 :(得分:1)

为了将状态提升到顶级组件,您需要将handleToken函数作为道具传递到登录组件中。

<Route path="/login" render={() => <Login userToken={this.state.token} handleToken={this.handleToken} />} />

然后,您还需要将其作为道具传递到FormContainer组件中。

<FormContainer handleToken={this.props.handleToken} />

最后,在您的fetch中,您需要在第二个.then()中调用此方法,而不是尝试将令牌分配给prop

this.props.handleToken(data.token)

这将允许将状态提升到父级,然后将令牌作为prop传递给您的其他组件。