Reactjs Antd上传添加到状态

Reactjs Antd上传添加到状态,reactjs,react-redux,antd,Reactjs,React Redux,Antd,我正在尝试使用antd Upload组件来更新用户配置文件图片,一旦完成,我想在其中添加图像url到状态。我很难真正理解动作道具背后的逻辑。。我想让用户上传图像,但只在点击“更新配置文件”按钮后将其提交到服务器 表单中的其他内容都可以正常工作,只是无法确定文件上载部分 我正在使用react+react redux,但似乎无法确定这一点,非常感谢任何帮助 表格: const initialState = { avatar: null, firstName: null, lastName

我正在尝试使用antd Upload组件来更新用户配置文件图片,一旦完成,我想在其中添加图像url到状态。我很难真正理解动作道具背后的逻辑。。我想让用户上传图像,但只在点击“更新配置文件”按钮后将其提交到服务器

表单中的其他内容都可以正常工作,只是无法确定文件上载部分

我正在使用react+react redux,但似乎无法确定这一点,非常感谢任何帮助

表格:

const initialState = {
  avatar: null,
  firstName: null,
  lastName: null,
  email: null,
  phone: null,
  gender: null,
  maritalStatus: null,
  educationLevel: null,
  income: null,
};

const AboutMeForm = ({ user: { user }, updateUser, getUser }) => {
  const [formData, setFormData] = useState({});
  const [form] = Form.useForm();

  useEffect(() => {
    if (!user) getUser();
    if (user) {
      const userData = { ...initialState };
      for (const key in user) {
        if (key in userData) userData[key] = user[key];
      }
      setFormData(userData);
    }
    form.setFieldsValue({
      firstName: formData.firstName,
      lastName: formData.lastName,
      email: formData.email,
      phone: formData.phone,
      gender: formData.gender,
      maritalStatus: formData.maritalStatus,
      educationLevel: formData.educationLevel,
      income: formData.income,
    });
  }, [
    getUser,
    user,
    form,
    formData.firstName,
    formData.lastName,
    formData.email,
    formData.phone,
    formData.gender,
    formData.maritalStatus,
    formData.educationLevel,
    formData.income,
  ]);

  const getBase64 = (img, callback) => {
    const reader = new FileReader();
    reader.addEventListener('load', () => callback(reader.result));
    reader.readAsDataURL(img);
  };

  const beforeUpload = (file) => {
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
    if (!isJpgOrPng) {
      notification['error']({
        message: `Uh oh!`,
        description: `You can only upload JPG/PNG files.`,
      });
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      notification['error']({
        message: `Uh oh!`,
        description: `Image must smaller than 2MB!`,
      });
    }
    return isJpgOrPng && isLt2M;
  };

  const onUploadAvatar = (info) => {
    if (info.file.status === 'done') {
      getBase64(info.file.originFileObj, (imageUrl) =>
        setFormData({ ...formData, avatar: imageUrl })
      );
      notification['success']({
        message: `Wahoo!`,
        description: `Profile picture successfully updated.`,
      });
    }
  };

  const onRemoveAvatar = () => {
    setFormData({ ...formData, avatar: null });
  };

  const onSubmit = (formData) => {
    updateUser(formData);
  };

  return (
    <>
      <Alerts />
      <Flex
        alignItems="center"
        mobileFlex={false}
        className="text-center text-md-left mb-4"
      >
        <Avatar size={90} src={formData.avatar} icon={<UserOutlined />} />
        <div className="ml-md-3 mt-md-0 mt-3">
          <Upload
            onChange={onUploadAvatar}
            showUploadList={false}
            action={avatarEndpoint}
            beforeUpload={beforeUpload}
          >
            <Button type="primary">Change Avatar</Button>
          </Upload>
          <Button className="ml-2" onClick={onRemoveAvatar}>
            Remove
          </Button>
        </div>
      </Flex>
      <Form
        form={form}
        name="aboutMe"
        layout="vertical"
        initialValues={initialState}
        onFinish={onSubmit}
      >
        <Row>
          <Col xs={24} sm={24} md={24} lg={16}>
            <Row gutter={ROW_GUTTER}>
              <Col xs={24} sm={24} md={12}>
                <Form.Item
                  label="First Name"
                  name="firstName"
                  rules={[
                    {
                      required: true,
                      message: 'First Name is required',
                    },
                  ]}
                >
                  <Input placeholder="Enter your First Name" />
                </Form.Item>
              </Col>
              ... other form fields
            </Row>
            <Button type="primary" htmlType="submit">
              Update Account
            </Button>
          </Col>
        </Row>
      </Form>
    </>
  );
};

AboutMeForm.propTypes = {
  updateProfile: PropTypes.func.isRequired,
  getProfile: PropTypes.func.isRequired,
  profile: PropTypes.object.isRequired,
  updateUser: PropTypes.func.isRequired,
  getUser: PropTypes.func.isRequired,
  user: PropTypes.object.isRequired,
};

const mapStateToProps = (state) => ({
  user: state.user,
  profile: state.profile,
});

export default connect(mapStateToProps, {
  updateProfile,
  getProfile,
  updateUser,
  getUser,
})(AboutMeForm);
// Update User
export const updateUser = (formData) => async (dispatch) => {
  try {
    const res = await api.post('/users/me/update', formData);

    dispatch({
      type: UPDATE_USER,
      payload: res.data,
    });

    dispatch(
      setAlert(
        'Bada-Bing!',
        'Your profile has successfully been updated.',
        'success'
      )
    );
  } catch (error) {
    const errors = error.response.data.errors;

    if (errors) {
      errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
    }

    dispatch({
      type: USER_ERROR,
      payload: {
        msg: error.response.statusText,
        status: error.response.status,
      },
    });
  }
};
const initialState = {
  user: null,
  loading: true,
  error: {},
};

export default function (state = initialState, action) {
  const { type, payload } = action;

  switch (type) {
    case GET_USER:
    case UPDATE_USER:
      return {
        ...state,
        user: payload,
        loading: false,
      };
    case USER_ERROR:
      return {
        ...state,
        error: payload,
        loading: false,
        user: null,
      };
    case CLEAR_USER:
      return {
        ...state,
        user: null,
      };
    default:
      return state;
  }
}
减速器:

const initialState = {
  avatar: null,
  firstName: null,
  lastName: null,
  email: null,
  phone: null,
  gender: null,
  maritalStatus: null,
  educationLevel: null,
  income: null,
};

const AboutMeForm = ({ user: { user }, updateUser, getUser }) => {
  const [formData, setFormData] = useState({});
  const [form] = Form.useForm();

  useEffect(() => {
    if (!user) getUser();
    if (user) {
      const userData = { ...initialState };
      for (const key in user) {
        if (key in userData) userData[key] = user[key];
      }
      setFormData(userData);
    }
    form.setFieldsValue({
      firstName: formData.firstName,
      lastName: formData.lastName,
      email: formData.email,
      phone: formData.phone,
      gender: formData.gender,
      maritalStatus: formData.maritalStatus,
      educationLevel: formData.educationLevel,
      income: formData.income,
    });
  }, [
    getUser,
    user,
    form,
    formData.firstName,
    formData.lastName,
    formData.email,
    formData.phone,
    formData.gender,
    formData.maritalStatus,
    formData.educationLevel,
    formData.income,
  ]);

  const getBase64 = (img, callback) => {
    const reader = new FileReader();
    reader.addEventListener('load', () => callback(reader.result));
    reader.readAsDataURL(img);
  };

  const beforeUpload = (file) => {
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
    if (!isJpgOrPng) {
      notification['error']({
        message: `Uh oh!`,
        description: `You can only upload JPG/PNG files.`,
      });
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      notification['error']({
        message: `Uh oh!`,
        description: `Image must smaller than 2MB!`,
      });
    }
    return isJpgOrPng && isLt2M;
  };

  const onUploadAvatar = (info) => {
    if (info.file.status === 'done') {
      getBase64(info.file.originFileObj, (imageUrl) =>
        setFormData({ ...formData, avatar: imageUrl })
      );
      notification['success']({
        message: `Wahoo!`,
        description: `Profile picture successfully updated.`,
      });
    }
  };

  const onRemoveAvatar = () => {
    setFormData({ ...formData, avatar: null });
  };

  const onSubmit = (formData) => {
    updateUser(formData);
  };

  return (
    <>
      <Alerts />
      <Flex
        alignItems="center"
        mobileFlex={false}
        className="text-center text-md-left mb-4"
      >
        <Avatar size={90} src={formData.avatar} icon={<UserOutlined />} />
        <div className="ml-md-3 mt-md-0 mt-3">
          <Upload
            onChange={onUploadAvatar}
            showUploadList={false}
            action={avatarEndpoint}
            beforeUpload={beforeUpload}
          >
            <Button type="primary">Change Avatar</Button>
          </Upload>
          <Button className="ml-2" onClick={onRemoveAvatar}>
            Remove
          </Button>
        </div>
      </Flex>
      <Form
        form={form}
        name="aboutMe"
        layout="vertical"
        initialValues={initialState}
        onFinish={onSubmit}
      >
        <Row>
          <Col xs={24} sm={24} md={24} lg={16}>
            <Row gutter={ROW_GUTTER}>
              <Col xs={24} sm={24} md={12}>
                <Form.Item
                  label="First Name"
                  name="firstName"
                  rules={[
                    {
                      required: true,
                      message: 'First Name is required',
                    },
                  ]}
                >
                  <Input placeholder="Enter your First Name" />
                </Form.Item>
              </Col>
              ... other form fields
            </Row>
            <Button type="primary" htmlType="submit">
              Update Account
            </Button>
          </Col>
        </Row>
      </Form>
    </>
  );
};

AboutMeForm.propTypes = {
  updateProfile: PropTypes.func.isRequired,
  getProfile: PropTypes.func.isRequired,
  profile: PropTypes.object.isRequired,
  updateUser: PropTypes.func.isRequired,
  getUser: PropTypes.func.isRequired,
  user: PropTypes.object.isRequired,
};

const mapStateToProps = (state) => ({
  user: state.user,
  profile: state.profile,
});

export default connect(mapStateToProps, {
  updateProfile,
  getProfile,
  updateUser,
  getUser,
})(AboutMeForm);
// Update User
export const updateUser = (formData) => async (dispatch) => {
  try {
    const res = await api.post('/users/me/update', formData);

    dispatch({
      type: UPDATE_USER,
      payload: res.data,
    });

    dispatch(
      setAlert(
        'Bada-Bing!',
        'Your profile has successfully been updated.',
        'success'
      )
    );
  } catch (error) {
    const errors = error.response.data.errors;

    if (errors) {
      errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
    }

    dispatch({
      type: USER_ERROR,
      payload: {
        msg: error.response.statusText,
        status: error.response.status,
      },
    });
  }
};
const initialState = {
  user: null,
  loading: true,
  error: {},
};

export default function (state = initialState, action) {
  const { type, payload } = action;

  switch (type) {
    case GET_USER:
    case UPDATE_USER:
      return {
        ...state,
        user: payload,
        loading: false,
      };
    case USER_ERROR:
      return {
        ...state,
        error: payload,
        loading: false,
        user: null,
      };
    case CLEAR_USER:
      return {
        ...state,
        user: null,
      };
    default:
      return state;
  }
}