发布于 2026-01-06 0 阅读
0

使用 React 和 Redux 构建公司主题简历生成器

使用 React 和 Redux 构建公司主题简历生成器

本指南将帮助您使用 Reactjs 构建一个公司主题的简历生成器。您只需填写个人信息,然后选择您想要申请的公司。该 Web 应用程序将根据您申请的公司自动生成简历。

步骤 1 - 设置 Redux store

首先,我们需要创建一个 store 来存储应用程序的状态树。我在 index.js 文件中创建了这个 store。要将状态的任何更改应用到 Redux 中,我们需要分发 action 并编写其 reducer 函数。

const store = createStore(rootReducer);
Enter fullscreen mode Exit fullscreen mode

然后我们将 App 组件包裹在 Provider 组件中。这样,所有嵌套组件都可以访问 Redux store。

<Provider store={store}>
      <App />
</Provider>
Enter fullscreen mode Exit fullscreen mode

现在,我们在所有其他组件内部都使用了一个连接函数。这样,​​每当状态更新时,该组件就可以重新读取状态值。

const mapStateToProps = (state) => {
    return{
        state
    }
};
const TwitterContainer = connect(mapStateToProps, null)(Twitter);
export default TwitterContainer;
Enter fullscreen mode Exit fullscreen mode

`Connect()` 函数接受两个参数,这两个参数都是可选的。我只使用了第一个参数:`mapStateToProps`。它会在每次 store 状态改变时被调用。它接收整个 store 状态,并返回该组件所需的数据对象。

步骤 2 - 从用户处获取详细信息

创建输入字段是为了获取用户输入。这些输入包括姓名、联系电话、电子邮件地址、工作经历、教育背景、项目、技能以及 LinkedIn 和作品集的链接。状态包含这些信息作为属性,初始状态为空。工作经历、教育背景、项目和技能均使用数组存储。数组中的每个元素包含:
1) ID;
2) 子标题;
3) 描述。

work_experience: [{
            id: 1,
            subheading: '',
            desc: ''
        }
]
Enter fullscreen mode Exit fullscreen mode

在这些字段中输入内容后,将会触发一个操作。

const addName = (value) => {
        props.dispatch({
          type: "ADD_NAME",
          text: value
        });
 }
Enter fullscreen mode Exit fullscreen mode

reducer会检查 action 的类型并相应地更改状态。要获取工作经验、教育背景、项目和技能等字段的输入,还需要 id。

以下代码用于工作示例的子标题。

const addWorkSubheading = (i,value) =>{
        props.dispatch({
            type: 'ADD_WORK_SUBHEADING',
            id: i,
            text: value
        });
 }
Enter fullscreen mode Exit fullscreen mode

类似地,也会针对其他子标题和描述执行相应的操作。

为了根据用户输入更改状态,首先将 action.id 与 work-ex 数组中所有元素的 id 进行比较,并将要更改的子部分赋值给一个变量,将其索引赋值给另一个变量。
现在,如果数组长度为 1,则使用扩展运算符展开状态,然后在 work-ex 数组中展开第一个元素并赋值。
如果长度为 2,则展开状态并使用 switch 语句检查子部分的索引。如果索引为 0,则更改第一个元素并返回第二个元素,反之亦然。
如果长度大于 2,则展开状态并从 0 到 subsectionIndex 切片 work-ex 数组并返回,展开所需的子部分并进行更改,然后再次从 (subsectionIndex + 1) 切片到末尾并返回。

case 'ADD_WORK_SUBHEADING':
            const subsection = state.work_experience.filter(w=>{ return w.id === action.id })[0];
            const subsectionIndex = state.work_experience.findIndex(w=>{ return w.id === action.id });
            if (state.work_experience.length <= 1){
                return{
                    ...state,
                    work_experience: [
                        {
                            ...state.work_experience[0],
                            subheading: action.text
                        }
                    ]
                };
            }
            else if (state.work_experience.length === 2) {
                switch (subsectionIndex) {
                    case 0:
                        return {
                            ...state,
                            work_experience: [
                                {
                                    ...state.work_experience[0],
                                    subheading: action.text
                                },
                                state.work_experience[1]
                            ]
                        };
                    case 1:
                        return {
                            ...state,
                            work_experience: [
                                state.work_experience[0],
                                {
                                    ...state.work_experience[1],
                                    subheading: action.text
                                }
                            ]
                        };
                }
            }
            else {
                return {
                    ...state,
                    work_experience: [
                        ...state.work_experience.slice(0, subsectionIndex),
                        {
                            ...subsection,
                            subheading: action.text
                        },
                        ...state.work_experience.slice(subsectionIndex+1, state.work_experience.length)
                    ]
                };
            }
Enter fullscreen mode Exit fullscreen mode

同样,其他子标题和描述的状态也会发生变化。

简历1

现在要添加子部分,这里有一个加号按钮。点击此按钮会触发一个 action。在 reducer 中,首先将 state 展开。然后展开 work-ex,并向数组中添加一个元素,该元素的 id 为数组长度加 1

case 'ADD_WORK_SUBSECTION':
            return {
            ...state,
            work_experience: [
                ...state.work_experience,
                {
                    id: state.work_experience.length+1,
                    subheading: '',
                    desc: ''

                } 
                ]
            };
Enter fullscreen mode Exit fullscreen mode

步骤三:预览简历

填写完详细信息后,您可以预览简历以用于不同公司。

简历2

点击这些按钮,即可获得您的专属主题简历。
用户输入的数据将根据您在此页面选择的公司以自定义样式显示。

步骤 4 - 使用 GitHub 登录

为了构建登录功能,我使用了 react-firebase auth。
使用 react-firebase 构建身份验证时,需要遵循以下步骤:

步骤 1

在 Firebase 中创建一个项目,并启用您希望在项目中使用的注册方式。

步骤 2

安装 React Firebase。npm
i @react-firebase/auth

步骤 3

使用以下链接获取您的 Firebase 配置:
https://console.firebase.google.com/project/PROJECT_NAME/settings/general/
将 PROJECT_NAME 替换为您的 Firebase 项目名称。
将此配置粘贴到名为 config.js 的文件中,然后导出配置

第四步

在项目中导入 Firebase。

import firebase from "firebase/app";
import "firebase/auth";
import {
  FirebaseAuthProvider,
  FirebaseAuthConsumer
} from "@react-firebase/auth";
import { config } from "./config";
Enter fullscreen mode Exit fullscreen mode

第五步

将您的应用代码封装在 FirebaseAuthProvider 和 FirebaseAuthConsumer 中:

<FirebaseAuthProvider firebase={firebase} {...config}>
<div>
            <FirebaseAuthConsumer>
            {({ isSignedIn, user, providerId}) => {
                if(isSignedIn === true){
                    return(
                        <div>
                            <Router>
                            <Switch>
                              <Route exact path="/" render={() => <MainApp uid={user.uid}/>} />
</div>
);
}
else{
                    return(
                      <div className="signin-div">
                        <button
                        className="signin"
                        onClick={() => {
                        const githubAuthProvider = new firebase.auth.GithubAuthProvider();
                        firebase.auth().signInWithPopup(githubAuthProvider);
                        }}>
                        Sign In with Github
                        </button>
                      </div>
                    );
                }

          }}
            </FirebaseAuthConsumer>
        </div>
      </FirebaseAuthProvider>
Enter fullscreen mode Exit fullscreen mode

如果用户已登录,FirebaseAuthConsumer 返回isSignedIn 为 true;如果没有用户登录,则返回false
。 根据此条件,要么渲染 MainApp 和所有其他组件,要么渲染一个包含注册按钮的页面。

步骤 5 - 将用户数据存储在 Firebase Cloud Firestore 中

以下步骤用于在 Cloud Firestore 中创建和存储数据。

步骤 1

进入你的项目并导航至 Cloud Firestore。选择启动模式为“测试模式”。选择位置并点击“完成”。

步骤 2

安装 Cloud Firestore SDK
:npm install firebase@8.4.3 --save

步骤 3

在你的项目中创建一个名为 database.js 的文件,并导入 firestore。

import firebase from "firebase/app";
import "firebase/firestore";
Enter fullscreen mode Exit fullscreen mode

第四步

初始化 Cloud Firestore 和数据库,并导出数据库。

firebase.initializeApp({
  apiKey: '### FIREBASE API KEY ###',
  authDomain: '### FIREBASE AUTH DOMAIN ###',
  projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});

const db = firebase.firestore();
export default db;
Enter fullscreen mode Exit fullscreen mode

将数据库导入到需要保存数据或获取数据的文件中

第五步

现在,要将数据保存到 Firestore 中,需要使用保存按钮。该按钮位于用户详情页面。

简历3

点击此按钮后,将运行以下代码。

const saveData = () => {
        db.collection("users").doc(props.uid).set({
            name: props.state.name,
            contact: props.state.contact,
            email: props.state.email,
            work_experience: props.state.work_experience,
            education: props.state.education,
            projects: props.state.projects,
            skills: props.state.skills,
            linkedin: props.state.linkedin,
            portfolio: props.state.portfolio
        })
        .then(() => {
            console.log("Document successfully written!");
        })
        .catch((error) => {
            console.error("Error writing document: ", error);
        });
    }
Enter fullscreen mode Exit fullscreen mode

运行这段代码后,数据库中会创建一个名为“users”的集合。身份验证时,我们会获取用户ID。数据库中会为不同的UID创建不同的文档。状态数据会使用`.set()`方法保存到数据库中。

步骤 6 - 从 Firebase Cloud Firestore 中检索用户数据

当主页挂载时,将从 Cloud Firestore 检索数据。

const fetchUsers = async () => {
        await db.collection("users").doc(props.uid).get().then((doc) => {
            if (doc.exists) {
                console.log("Document data:", doc.data().portfolio);
                props.dispatch({
                    type: "ADD_DATA",
                    text: doc.data()
                })
            } 
            else {
                console.log("No such document!");
            }
            }).catch((error) => {
            console.log("Error getting document:", error);
            });
    };

    useEffect( () => { fetchUsers() }, [] );
Enter fullscreen mode Exit fullscreen mode

使用useEffect 并传入一个空数组,我们不会监听任何变量。因此,它只会在组件首次渲染时(例如 componentDidMount())更新状态。
在 fetchUsers 函数内部,会调用 .get() 方法,并将 "users" 作为集合, "uid" 作为文档。它会检索该 uid 对应的数据。然后会分发一个 action,并在 reducer 函数中对状态进行如下更改。

case 'ADD_DATA':
            return{
            ...state,
            name: action.text.name,
            contact: action.text.contact,
            email: action.text.email,
            work_experience: action.text.work_experience,
            education: action.text.education,
            projects: action.text.projects,
            skills: action.text.skills,
            linkedin: action.text.linkedin,
            portfolio: action.text.portfolio,
            firebaseprocessing: false
            };
Enter fullscreen mode Exit fullscreen mode

步骤 7 - 分享简历链接

选择您想要创建简历的公司后,您将进入一个页面,页面上会显示您的简历和分享按钮。点击此按钮后,您将获得一个链接。请复制此链接并粘贴到您想要的位置。

简历4

要获取此链接,首先我们需要主机名、协议和端口。

const hostname = window.location.hostname;
const protocol = window.location.protocol;
const port = window.location.port;
Enter fullscreen mode Exit fullscreen mode

为了显示这个链接,需要创建一个包含该链接的 div 元素,该元素仅在点击分享按钮时可见,点击除该 div 元素之外的任何其他位置时都会消失。为此,我使用了 ClickAwayListener 。您可以在https://www.npmjs.com/package/react-click-away-listener上了解更多信息

{(props.state.link === true)?
                    <ClickAwayListener onClickAway={e=>hideLink()}>
                    <section className="link-part3" >
                        {(port === 0 || port === '')?
                            <p>Copy this link {protocol}//{hostname}/{props.uid}/amazon</p>:
                            <p>Copy this link {protocol}//{hostname}:{port}/{props.uid}/amazon</p> 
                        }
                    </section>
                    </ClickAwayListener>:
                    <Fragment />
                }
Enter fullscreen mode Exit fullscreen mode

在本代码段中,首先检查 `props.state.link` 是否为真。它用于显示链接。然后,检查端口号是否为 0、空字符串或其他值
如果端口号为 0 或空字符串,则表示默认情况(HTTP 使用 80 端口,HTTPS 使用 443 端口)。在默认情况下,链接中不需要指定端口号。
如果端口号不为 0 或空字符串,则需要在链接中指定端口号。
链接还会包含一个 uid,用于在用户点击链接时检索数据。

步骤 8 - 通过链接查看简历

为了表明该链接是从外部输入的,在路由该链接时,会将参数external传递给 props。

<Route path="/:id/youtube" render={() => <Youtube external={true} />}/>
Enter fullscreen mode Exit fullscreen mode

在 YouTube 组件内部,使用 useEffect 时,我们会检查 props.external 是否为 true。这用于判断链接是否来自外部。
如果 props.external 为 true,则会调用 fetchUsers 并传入用户 ID。我们使用链接中的 ID 来实现这一点,为此使用了 useParams()。
如果 props.external 为 false,则表示这是一个内部链接,此时会调用 fetchUsers 并传入 props.uid
这用于获取与当前用户 ID 对应的文档,该用户正在查看其简历。

const fetchUsers = async (i) => {
        await db.collection("users").doc(i).get().then((doc) => {
            if (doc.exists) {
                console.log("Document data:", doc.data().portfolio);
                props.dispatch({
                    type: "ADD_DATA",
                    text: doc.data()
                });
            } 
            else {
                console.log("No such document!");
            }
            }).catch((error) => {
            console.log("Error getting document:", error);
            });
    };

    useEffect( () => { 
        (props.external)?
        fetchUsers(id):
        fetchUsers(props.uid) 
    }, [] );
Enter fullscreen mode Exit fullscreen mode

现在,系统会从 Cloud Firestore 中检索用户数据,并据此更改状态。当用户点击任何链接时,系统会使用存储中的数据来显示恢复过程中的信息。

源代码:https://github.com/shambhavijs/themed-resume
在线演示:https://bit.ly/2SiZUZ4

文章来源:https://dev.to/shambhavijs/company-themed-resume-builder-using-react-and-redux-5153