Practical react technology stack + Express front end and back end blog project (4) — the writing of blog home page code and the organization of Redux Saga

Time:2021-6-9

Project address:https://github.com/Nealyang/R…

I wanted to wait for the project to finish and then serialize a series of blogs. With the development, I did encounter many pitfalls and consulted many people. So I thought, why not record and share the harvest at the same time. Sharing is good, of course,
It would be more beautiful if we could pool our wisdom. Our slogan is:We will never fail

This blog is a serial code blog, which is updated synchronously. With the development of the project in the future, we may encounter the inappropriate places written before, and then we will go back to modify them. If there is something wrong, please don’t be stingy. thank you!

Home page rendering (currently false data)

  • Not logged in

Practical react technology stack + Express front end and back end blog project (4) -- the writing of blog home page code and the organization of Redux Saga

  • Sign in

Practical react technology stack + Express front end and back end blog project (4) -- the writing of blog home page code and the organization of Redux Saga

Home part of the code

class Home extends Component {
    constructor(props) {
        super(props);
        this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this)
    }

    render() {
        const {login,register} = this.props;
        localStorage.setItem('userInfo',JSON.stringify(this.props.userInfo));
        return (
            this.props.match.params.tag && (tags.indexOf(this.props.match.params.tag) === -1 || this.props.location.pathname.lastIndexOf('\/') > 0)
                ?
                <Redirect to='/404'/>
                :
                <div className={style.container}>
                    <div className={style.contentContainer}>
                        <div className={`${style.newsContainer} ${anStyle.animated} ${anStyle.fadeInUp}`}>
                            <ArticleList/>
                            <div className={style.paginationContainer}>
                                <Pagination defaultCurrent={6} total={500}/>
                            </div>
                        </div>
                        <div className={`${style.loginContainer} ${anStyle.animated} ${anStyle.fadeInRight}`}>
                            {this.props.userInfo.userId?<Logined history={this.props.history} userInfo={this.props.userInfo}/>:<Login  login={login} register={register}/>}
                        </div>
                    </div>
                </div>
        )
    }
}

In the future, we will use tags as the route to display the list of articles under different tabs, so when the URL is not matched and the tag is not matched, we will display the 404 page.

The home page mainly includes the following items. Carousel chart (only used as UI here), tag, article list, paging, login function.

So for the part of complex coding, we separate out the components. For the home.js file, it is also the public page corresponding to clicking all the tags. It’s just that the list of articles is different.

Log in to register the form component

Other components are conventional coding. Let’s talk about the form component

class LoginFormCom extends Component {
    constructor(props) {
        super(props);
    }

    handleLogin = (e) => {
        e.preventDefault();
        this.props.form.validateFields((err, values) => {
            if (!err) {
                this.props.login(values.userName,values.password)
            }
        });
    };

    render() {
        const {getFieldDecorator} = this.props.form;
        return (
            <Form onSubmit={this.handleLogin} className={style.formStyle}>
                <FormItem>
                    {getFieldDecorator('userName', {
                        Rules: [{required: true, message: 'please enter user name!'}],
                    })(
                        <Input prefix={<Icon type="user" style={{fontSize: 13}}/>} placeholder="Username"/>
                    )}
                </FormItem>
                <FormItem>
                    {getFieldDecorator('password', {
                        Rules: [{required: true, message: 'please enter password!'}],
                    })(
                        <Input prefix={<Icon type="lock" style={{fontSize: 13}}/>} type="password"
                               placeholder="Password"/>
                    )}
                </FormItem>
                <FormItem>
                    <Button className={style.loginButton} type="primary" htmlType="submit">
                        Sign in
                    </Button>
                </FormItem>
            </Form>
        )
    }
}

const LoginForm = Form.create()(LoginFormCom);

export default LoginForm

Here I will login and register separately out to write two components. For details, please refer to the official document of antd.

Saga section

Saga mentioned in this part is only saga of some global information, including error message reminder, global loading, login status, etc. Saga that is not the first page article list tag

reducer

const initialState = {
    isFetching: true,
    msg: {
        Type: 1, // 0 failed 1 succeeded
        content: ''
    },
    userInfo: {}
};

export const actionsTypes = {
    FETCH_START: "FETCH_START",
    FETCH_END: "FETCH_END",
    USER_LOGIN: "USER_LOGIN",
    USER_REGISTER: "USER_REGISTER",
    RESPONSE_USER_INFO: "RESPONSE_USER_INFO",
    SET_MESSAGE: "SET_MESSAGE",
    USER_AUTH:"USER_AUTH"
};

export const actions = {
    get_login: function (username, password) {
        return {
            type: actionsTypes.USER_LOGIN,
            username,
            password
        }
    },
    get_register: function (data) {
        return {
            type: actionsTypes.USER_REGISTER,
            data
        }
    },
    clear_msg: function () {
        return {
            type: actionsTypes.SET_MESSAGE,
            msgType: 1,
            msgContent: ''
        }
    },
    user_auth:function () {
        return{
            type:actionsTypes.USER_AUTH
        }
    }
};

export function reducer(state = initialState, action) {
    switch (action.type) {
        case actionsTypes.FETCH_START:
            return {
                ...state, isFetching: true
            };
        case actionsTypes.FETCH_END:
            return {
                ...state, isFetching: false
            };
        case actionsTypes.SET_MESSAGE:
            return {
                ...state,
                isFetching: false,
                msg: {
                    type: action.msgType,
                    content: action.msgContent
                }
            };
        case actionsTypes.RESPONSE_USER_INFO:
            return {
                ...state, userInfo: action.data
            };
        default:
            return state
    }
}

// const front = combineReducers({
//    // home
// });

export default combineReducers({
    // front,
    globalState: reducer,
    admin
})

Let’s talk about the next few states.

FETCH_ Start: "start asynchronous request,",
    FETCH_ End: "asynchronous request end,",
    USER_ Login: "user login",
    USER_ Register: "user registration",
    RESPONSE_ USER_ Info: "login information received",
    SET_ Message: "set global reminder",
    USER_ AUTH:"USER_ Auth "// no login later

The processing of saga in correspondence

export function* login(username, password) {
    yield put({type: IndexActionTypes.FETCH_START});
    try {
        return yield call(post, '/user/login', {username, password})
    } catch (error) {
        yield put({ type:IndexActionTypes.SET_ Message, msgcontent: 'wrong user name or password', msgt ype:0 });
    } finally {
        yield put({type: IndexActionTypes.FETCH_END});
    }
}

export function* register (data) {
    yield put({type:IndexActionTypes.FETCH_START});
    try {
        return yield call(post, '/user/register', data)
    } catch (error) {
        yield put({ type:IndexActionTypes.SET_ Message, msgcontent: 'registration failed', msgt ype:0 });
    } finally {
        yield put({type: IndexActionTypes.FETCH_END});
    }
}

export function* loginFlow() {
    while (true) {
        let request = yield take(IndexActionTypes.USER_LOGIN);
        let response = yield call(login, request.username, request.password);
        if(response&&response.code === 0){
            yield put({ type:IndexActionTypes.SET_ Message, msgcontent: 'login succeeded! ", msgT ype:1 });
            yield put({type:IndexActionTypes.RESPONSE_USER_INFO,data:response.data})
        }
    }
}

export function* registerFlow () {
    while(true){
        let request = yield take(IndexActionTypes.USER_REGISTER);
        let response = yield call(register, request.data);
        if(response&&response.code === 0){
            yield put({ type:IndexActionTypes.SET_ Message, msgcontent: 'registration successful! ", msgT ype:1 });
            yield put({type:IndexActionTypes.RESPONSE_USER_INFO,data:response.data})
        }

    }
}

export function* user_auth () {
    while(true){
        yield take(IndexActionTypes.USER_AUTH);
        try {
            yield put({type:IndexActionTypes.FETCH_START});
            let response = yield call(get,'/user/userInfo');
            if(response && response.code === 0){
                yield put({type:IndexActionTypes.RESPONSE_USER_INFO,data:response.data})
            }
        }catch (err){
            console.log(err);
        }finally {
            yield put({type: IndexActionTypes.FETCH_END});
        }
    }
}

Saga mainly deals with user login and registration. In each saga processing function, you need to put an action to start and end the request. If the request is wrong, you need to set the global status alert.

user_ Auth is a saga processing without logging in later. You can skip the following introduction.

summary

As mentioned above, when logging in, we will dispatch a login action, saga will capture the action, and then after corresponding processing, put the corresponding action to the reducer.

Specific operation, you can view the code on GitHub


This part is mainly front-end operation, so the code part is in the / APP folder.


Project implementation steps series blog

communication

If you have something you don’t understand or need to communicate with me, you are welcome to mention issue. Or add a group to contact me~

Scan code concerns my personal WeChat official account, and reply directly, there must be a response. Share more original articles. Click exchange learning plus wechat and QQ group. Study together and make progress together

Practical react technology stack + Express front end and back end blog project (4) -- the writing of blog home page code and the organization of Redux Saga


Welcome to join us

Node.js technology exchange group: 209530601

React technology stack: 398240621

Front end technology: 604953717 (New)