嗨,我正在做一个应用程序,我有一个注册页面与表格,我注册了一个用户,并通过我的API与NodeJS通过我的POST路由发送数据.

我能够做到这一点,没有不便,但我知道,随着我的应用程序将增长和有几个功能,它会更好,如果我使用redux工具包.

这就是我正在做的事情.

import React, { useState } from 'react'
import axios from 'axios'

//Material UI
import {Grid, Container, Box, Button, FormControl, InputLabel, Input, FormHelperText } from '@mui/material'

function Register() {
    
    const [ formData, setFormData ] = useState({
        name: '',
        email: '',
        password: '',
        password2: ''
    })

    const { name, email, password, password2 } = formData; 

    const onChange = e => setFormData({...formData, [e.target.name]: e.target.value})

    const onSubmit = async (e) => {
        e.preventDefault();
        if(password !== password2){
            console.log("Passwords do not match");
        } else {
            const newUser = {
                name: formData.name,
                email: formData.email,
                password: formData.password
            }

            try {
                const config = {
                    headers: {
                        'Content-Type': 'application/json'
                    }
                }

                const body = JSON.stringify(newUser);
                const res = await axios.post('http://localhost:3000/api/users', body, config)
                console.log(res.data)

            } catch (error) {
                console.error(error.response.data)
            }
        
        }
    }

    return (
    <Container>
        <Box p={4}>
            <Grid container  >
                <form onSubmit={e => onSubmit(e)}>
                    <Grid item md={12}>
                        <FormControl>
                            <InputLabel htmlFor="name">Name</InputLabel>
                            <Input 
                            type='text' 
                            id='name' 
                            name='name'
                            value={name}
                            onChange={e => onChange(e)}
                            />
                            <FormHelperText>Insert your complete name</FormHelperText>
                        </FormControl>
                    </Grid> 
                    <Grid item md={12}>
                        <FormControl>
                            <InputLabel htmlFor="email">Email</InputLabel>
                            <Input 
                            id='email' 
                            type='email' 
                            name='email'
                            value={email}
                            onChange={e => onChange(e)}
                            />
                            <FormHelperText>Insert your email</FormHelperText>
                        </FormControl>
                    </Grid>
                    <Grid item md={12}>    
                        <FormControl>
                            <InputLabel htmlFor="password">Password</InputLabel>
                            <Input 
                            id="password" 
                            type='password' 
                            name='password'
                            value={password}
                            onChange={e => onChange(e)}
                            />
                            <FormHelperText>Insert your password (must have at least 6 characters)</FormHelperText>
                        </FormControl>
                    </Grid>
                    <Grid item md={12}>    
                        <FormControl>
                            <InputLabel htmlFor="password2">Confirm Password</InputLabel>
                            <Input 
                            id="password2" 
                            type='password'
                            name='password2' 
                            value={password2}
                            onChange={e => onChange(e)}
                            />
                            <FormHelperText>Insert your password (must have at least 6 characters)</FormHelperText>
                        </FormControl>
                    </Grid>
                    <Grid item md={12}>    
                        <Button type='submit' variant="contained" color="primary">
                            Register
                        </Button>
                    </Grid>
                </form>
            </Grid>
        </Box>
    </Container>
  )
}

export default Register

我现在想try 并开始使用redux清理我的代码和管理状态,但我仍然对这个库感到非常困惑,我不知道如何继续.

我已经创建了一个store ,并将其传递给供应商,但我在理解切片方面遇到了困难.

这就是我到目前为止所拥有的:

import { createSlice } from '@reduxjs/toolkit'

const initialState = {
    token: localStorage.getItem('token'),
    isAuthenticated: null,
    loading: true,
    user: null
}

export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    
  },
})

// Action creators are generated for each case reducer function
export const {  } = counterSlice.actions

export default counterSlice.reducer

因此,如果我通过表单发送的数据没有错误,我会得到一个令牌.我想让两个Reducer函数,一个用来注册我的用户,而不是把所有代码块放在我的组件中,另一个用我之前收到的令牌来验证用户.

推荐答案

减法器是接收当前状态和操作对象,并计算和返回下一个状态值的函数.Reducer并不是会产生像进行API调用这样的副作用的代码,这就是操作的目的.操作被调度到存储区,并对状态进行更改.异步操作被分派到存储,并由一些中间件处理,而不会立即将操作移交给Reducer树.100要将用户注册逻辑移入的部分.

createAsyncThunk

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

export const registerUser = createAsyncThunk(
  "user/register",
  async (newUser, thunkAPI) => {
    try {
      const config = {
        headers: {
          'Content-Type': 'application/json'
        }
      }

      const body = JSON.stringify(newUser);
      const { data } = await axios.post('http://localhost:3000/api/users', body, config);
      console.log(data);
      localStorage.setItem("token", JSON.stringify(data));
      return data;
    } catch (error) {
      console.error(error.response.data);
      return thunkAPI.rejectWithValue(error.response.data);
    }
  },
);

export const verifyToken = createAsyncThunk(
  "user/verifyToken",
  async (token, thunkAPI) => {
    try {
      const { data } = await axios.get(.....);
      return data;
    } catch(error) {
      return thunkAPI.rejectWithValue(/* error */);
    }
  }
);

const initialState = {
  token: JSON.parse(localStorage.getItem('token') ?? ""),
  isAuthenticated: null,
  loading: false,
  user: null,
  error: null,
};

export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    ... any regular reducer cases ...
  },
  extraReducers: builder => {
    builder
      .addCase(registerUser.pending, (state) => {
        state.loading = true;
      })
      .addCase(registerUser.fulfilled, (state, action) => {
        state.loading = false;
        state.token = action.payload; // <-- no errors, response is token
      })
      .addCase(registerUser.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload; // <-- error response
      })
      .addCase(verifyToken.pending, (state) => {
        state.loading = true;
      })
      .addCase(verifyToken.fulfilled, (state, action) => {
        state.loading = false;
        state.user = action.payload;
        state.isAuthenticated = true;
      })
      .addCase(verifyToken.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload;
        state.isAuthenticated = false;
      });
  },
});

// Action creators are generated for each case reducer function
export const {  } = counterSlice.actions;

export default counterSlice.reducer;

我不得不在某种程度上使用令牌验证/身份验证,但这个示例应该是一个很好的起点.

现在,Register组件将使用useDispatch挂钩AN dispatch函数将registerUserverifyToken操作分派到存储,并按顺序等待每个操作.

...
import { useDispatch, useSelector } from 'react-redux';
...
import { registerUser, verifyToken } from '../path/to/user.slice';

function Register() {
  const dispatch = useDispatch();
  const isLoading = useSelector(state => state.user.loading);
   
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    password2: ''
  });

  ...

  const onSubmit = async (e) => {
    e.preventDefault();

    if (password !== password2) {
      console.log("Passwords do not match");
    } else {
      const { name, email, password } = formData;
      const newUser = { name, email, password };

      try {
        const token = await dispatch(registerUser(newUser)).unwrap();
        await dispatch(verifyToken(token));
        // user successfully registered and token verified/authenticated
        // maybe redirect to home page? ??‍♂️ world is your oyster.
      } catch (error) {
        console.error(error);
      }
    }
  };

  if (isLoading) {
    return <LoadingSpinner />;
  }

  return (
    ...
  );
}

export default Register;

createAsyncThunk和API调用的"挂起"/"已完成"/"已拒绝"的模式非常常见.react-redux团队通过Redux Toolkit Query(RTKQ)创建了额外的专用API切片.Redux工具包(RTK)对旧的Redux所做的react Redux以减少样板代码,RTKQ对RTK所做的是管理API调用的异步操作.

因为你在Redux才刚刚开始,所以我建议你先学习基础知识,以便更好地掌握,但我强烈建议你在可能的时候go 探索RTKQ.

Reactjs相关问答推荐

运行 node server.js会导致以下错误:Route.post()需要回调函数,但在Route.&处得到了[对象Undefined] lt;计算>

Inbox Enum类型以React组件状态时出现TypScript错误

Redux向后端发送请求时出现钩子问题

为什么安装FLOBIT后,所有的输入FIELD现在都有一个蓝色的轮廓?

我想删除NextJs中的X轴标签APEXCHARTS

如何在单击行中的图标时避免选中ionic 复选框?

在Reaction中单击并显示子组件延迟/动画

Google Firestore无法读取图像-react

在Map()完成React.js中的多个垃圾API请求后执行函数

当useEffect和onClick处理程序都调用useCallback函数时,有没有办法对useEffect产生额外的影响?

在继承值更改时重置react 挂钩窗体字段值

如何在物料界面react 的多选菜单中设置最大 Select 数限制

React组件未出现

React useEffect 问题...异步函数内的变量正在获取延迟的更新值

预期无限重新渲染但没有发生

无法使用react-hook-form和react-places-autocomplete在字段中输入值

修改React数据表扩展组件

从ReactDataGridtry 将数据传递给父组件

React:如何使用条件渲染和react 挂钩来更新另一个组件的状态?

React Hooks 表单在日志(log)中显示未定义的用户名