【问题标题】:Converting class based component to function based component fails将基于类的组件转换为基于函数的组件失败
【发布时间】:2021-07-23 08:03:07
【问题描述】:

我正在从基于类的组件切换到基于函数的组件,但我的代码在基于类的组件中工作,在基于函数的组件中不起作用。

代码如下:

import { connect } from "react-redux";
import * as actions from "../redux/actions/authActions";

class Login extends Component {
  constructor(props) {
    super(props);
    this.state = {
      email: "",
      password: "",
    };
  }

  authenticate() {
    this.props.auth(this.state.email, this.state.password).then((response) => {
      if (this.props.authenticated) {
        alert("User Is Authenticated");
      } else {
        alert("User Isn't Authenticated");
      }
    });
  }

  render() {
    return (
      <View style={{ flex: 1 }}>
        <TextInput
          autoCapitalize="none"
          keyboardType="email-address"
          style={// styles here}
          placeholder="Enter email"
          value={this.state.email}
          onChangeText={(email) => this.setState({ email })}
        />
        <TextInput
          autoCapitalize="none"
          secureTextEntry
          style={// styles here}
          placeholder="Enter password"
          value={this.state.password}
          onChangeText={(password) => this.setState({ password })}
        />
        <TouchableOpacity onPress={() => this.authenticate()}>
          <Text style={{ marginTop: 20, color: "black", textAlign: "center" }}>
            Login
          </Text>
        </TouchableOpacity>
      </View>
    );
  }
}

const mapStateToProps = (state) => ({
  isLoggedIn: state.auth.isLoggedIn,
  isLoading: state.auth.isLoading,
  userData: state.auth.userData,
  error: state.auth.error,
  authenticated: state.auth.isAuthenticated,
  mainState: state,
});

const mapDispatchToProps = (dispatch) => ({
  auth: (email, password) => dispatch(actions.loginUser({ email, password })),
});

export default connect(mapStateToProps, mapDispatchToProps)(Login);

将代码转换为基于函数的组件

import { connect } from "react-redux";
import * as actions from "../redux/actions/authActions";

function Login({ auth, authenticated }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const authenticate = () => {
    auth(email, password).then((response) => {
      if (authenticated) {
        alert("User Is Authenticated");
      } else {
        alert("User Isn't Authenticated");
      }
    });
  };

  return (
    <View style={{ flex: 1 }}>
      <TextInput
        autoCapitalize="none"
        keyboardType="email-address"
        style={ // styles here}
        placeholder="Enter email"
        value={email}
        onChangeText={(text) => setEmail(text)}
      />
      <TextInput
        autoCapitalize="none"
        secureTextEntry
        style={ // styles here}
        placeholder="Enter password"
        value={password}
        onChangeText={(text) => setPassword(text)}
      />
      <TouchableOpacity onPress={() => authenticate()}>
        <Text style={{ marginTop: 20, color: "black", textAlign: "center" }}>
          Login
        </Text>
      </TouchableOpacity>
    </View>
  );
}

const mapStateToProps = (state) => ({
  isLoggedIn: state.auth.isLoggedIn,
  isLoading: state.auth.isLoading,
  userData: state.auth.userData,
  error: state.auth.error,
  authenticated: state.auth.isAuthenticated,
  mainState: state,
});

const mapDispatchToProps = (dispatch) => ({
  auth: (email, password) => dispatch(actions.loginUser({ email, password })),
});

export default connect(mapStateToProps, mapDispatchToProps)(Login);

这里是Login 函数。应用状态不会在第一次更新,但会在后续尝试中更新。

感谢您的阅读和帮助。

【问题讨论】:

  • 在第二次点击登录按钮时,它可以工作,但不是第一次?
  • 功能组件中的按钮在第一次和第二次点击时都有效,但在第一次点击时,即使我看到服务器的响应props.authenticatedtrue,它总是在第一次显示false
  • 该代码在基于类的组件中有效,但在基于函数的组件中无效。

标签: javascript reactjs react-native function class


【解决方案1】:

您已经关闭了调用 authenticate 的渲染周期中的陈旧状态。React 状态更新是异步的,因此如果您想在更新后处理状态,您可能需要在下一个渲染周期中这样做在 useEffect 钩子中(与基于类的组件的 componentDidUpdate 方法同义)。当authenticated redux 状态值更新时,组件会重新渲染。

useEffect(() => {
  if (authenticated) {
    alert("User Is Authenticated");
  } else {
    alert("User Isn't Authenticated");
  }
}, [authenticated]);

authenticate() {
  auth(email, password)
    .then((response) => {
      console.log(response);      
    });
}

更新

这个useEffect 回调将显示一个警报或另一个,每次渲染。您可以添加状态以使其等到您提交身份验证请求并通过身份验证。

const [isAuthenticating, setIsAuthenticating] = useState(false);
const [finishedAuth, setFinishedAuth] = useState(false);

useEffect(() => {
  if (isAuthenticating && finishedAuth) {
    alert(authenticated
      ? "User Is Authenticated"
      : "User Isn't Authenticated"
    );
  }
}, [isAuthenticating, finishedAuth, authenticated]);

authenticate() {
  setIsAuthenticating(true);
  auth(email, password)
    .then((response) => {
      console.log(response);
    })
    .finally(() => setFinishedAuth(true));
}

这两个额外的状态可能是存储在您的 redux 状态中的绝佳候选者,顺便说一句。

【讨论】:

  • 谢谢,看来我已经很接近了,但是当我进入登录屏幕时,它会立即弹出上述警报“用户未通过身份验证”。尽管如此,我没有在电子邮件和密码字段中输入任何内容,也没有提交表单。
  • 现在可以正常工作了,非常感谢。我该如何解决最初的弹出窗口。
  • @NoorNoori 您可以添加其他条件,例如不要在初始渲染时调用,或者检查电子邮件和密码是否真实,或者可能只是添加您在身份验证时触发的其他状态,即“已提交身份验证请求”和“已通过身份验证”。
  • 您能否更新答案,为什么显示默认弹出窗口?感谢您的帮助
  • 嗨@DrewReese,我尝试创建一个类似的应用程序,但似乎没有遇到任何此类错误。我直接在第一次点击时获得值。你能帮我理解你的答案吗?为什么我的应用程序在第一次点击时也能正常运行?谢谢。 codesandbox.io/s/red-cdn-eg66n?file=/src/App.js
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 2020-10-27
相关资源
最近更新 更多