Project Address:Github.com/Nealyang/Re…

I wanted to serialize a series of blogs after the completion of the project, but as the development went on, I did meet many pits and consulted many people. So I thought, why not share the harvest while recording the pits. Sharing is good, of course, but it would be even more beautiful if we could pool our ideas. Our slogan is: never lose the tail

This blog for serial code blog synchronous update blog, with the future development of the project may encounter in front of the inappropriate place will be revised back. If there is anything wrong ~ welcome brothers don’t add to your comments. Thank you very much!

The previous content is modified

Since this blog is a simultaneous development and post serialization, the previous development code will be modified as development progresses.

Authority certification

Before the permission authentication, we only do part of the permission management. When the front-end page jumps, we check the state userInfo to determine whether the current login user has access.

However, there is a hidden danger, that is, I log in to a management interface as an administrator, but I did not perform any operation or jump before my identity expires, and kept on the back-end management interface. Then when my identity expired, I carried out some admin management operations (add, delete, change and check), and did not involve the page jump. The front end can’t be determined by the URL.

So, here we modify the front and back end to intercept all /admin API operations to determine if the identity is expired.

admin.js

Router.use ((req,res,next) =>{if(req.session.userinfo){next()}else{ Res. send(responseClient(res,200,1,' id has expired, please log in again ')); }});Copy the code

In the front-end saga we need to determine the information returned by the interface.

export function* delTagFlow() { while (true){ let req = yield take(ManagerTagsTypes.DELETE_TAG); let res = yield call(delTag,req.name); if (res.code === 0) { yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 1}); yield put({type:ManagerTagsTypes.GET_ALL_TAGS}); } else if (res.message === 'id has expired, please log in again ') {yield put({type: indexactiontypes.set_message, msgContent: res.message, msgType: 0}); setTimeout(function () { location.replace('/'); }, 1000); } else { yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 0}); }}}Copy the code

At present I don’t think it can be done once and for all. If you guys have good ideas, please comment on them and let us discuss them together

Front-end route extraction component

Before, we wrote a function directly in front of the page, but it didn’t make sense later, because I needed to change it into a container component. So here we need to pull out a class as a container

const {get_all_tags} = actions;

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

    render(){
        const {url} = this.props.match;
        return(
            <div>
                <div className={`${animationStyle.animated} ${animationStyle.fadeInDown}`}>
                    <Banner/>
                    <Menus categories={this.props.categories} history={this.props.history}/>
                </div>
                <Switch>
                    <Route exact path={url} component={Home}/>
                    <Route path={`/detail/:id`} component={Detail}/>
                    <Route path={`/:tag`} component={Home}/>
                    <Route component={NotFound}/>
                </Switch>
            </div>
        )
    }

    componentDidMount() {
        this.props.get_all_tags();
    }
}

Front.defaultProps = {
    categories:[]
};

Front.propTypes = {
    categories:PropTypes.array.isRequired
};

function mapStateToProps(state) {
    return{
        categories:state.admin.tags
    }
}
function mapDispatchToProps(dispatch) {
    return{
        get_all_tags:bindActionCreators(get_all_tags,dispatch)
    }
}
export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Front)
Copy the code

Home.js route judgment redirection

return ( tags.length>1&&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> )Copy the code

Here we need to determine the length of the tags, because now tags are retrieved asynchronously. So there’s jet lag. For example, naming can access the /Html tag, but since tags are retrieved asynchronously, when the current page is refreshed, the tags are not fully loaded, so they are redirected directly to the 404 page.

Label management operation effect display

I’m going to put two images here just to give you a sense of how big the GIF is.

  • The initial state

  • Add the tag

  • Front-end label changes

  • Remove the tag

  • Returning to the initial state, the /Vue refresh Redirect to 404

Back-end code section

Router.get ('/delTag', function (req, res) {let {name} = req.query; Then (result => {if(result.result.n === 1){responseClient(res,200,0,' delete successfully! ')}else{responseClient(res,200,1,' label not found '); } }).catch(err => { responseClient(res); }); }); Router. Post ('/addTag', function (req, res) {let {name} = req. Body; Tags.findOne({ name }).then(result => { if (! result) { let tag = new Tags({ name }); Tag.save (). Then (data => {responseClient(res, 200, 0, 'added successfully ', data); }). Catch (err => {throw err})} else {responseClient(res, 200, 1, 'this tag already exists '); } }).catch(err => { responseClient(res); }); }); module.exports = router;Copy the code

For clarity and ease of management, route directly under /tag. The usual operation is to delete and add labels.

To get all the tags, I put them outside of admin, because after all, the front-end page also needs this interface. If both are put into/API /admin/getAllTags, authentication will be performed on /admin requests. Therefore, it is not reasonable to put all tag interfaces under tags.

Here we choose to put it in main.js

Router.get ('/getAllTags', function (req, res) {finder.find (null,'name'). Then (data => {responseClient(res, 200, 0, 'request successful ', data); }).catch(err => { responseClient(res); })});Copy the code

Front-end modification

The modifications to the front-end organizational structure have been covered above. Here’s the processing in Saga

AdminTag interface code:

class AdminManagerTags extends Component{ constructor(props){ super(props); This. State ={tags: [' home ',' HTML', 'CSS','JAVASCRIPT'], inputVisible: false, inputValue: ",}} handleClose = (removedTag) => {// deleteTag this.props. showInput = () => { this.setState({ inputVisible: true }, () => this.input.focus()); }; handleInputChange = (e) => { this.setState({ inputValue: e.target.value }); }; HandleInputConfirm = () => {// Add the tag this.props. AddTag (this.state.inputValue); this.setState({ inputVisible: false, inputValue: '', }); }; saveInputRef = input => this.input = input; render(){ const { inputVisible, inputValue } = this.state; const {tags} = this.props; Return (<div> <h2 className={style.titlestyle}> tag management </h2> {tag.map ((tag, index) => {const isLongTag = tag.length > 20; const tagElem = ( <Tag className={style.tagStyle} key={index} closable={index ! == 0} afterClose={() => this.handleClose(tag)}> {isLongTag ? `${tag.slice(0, 20)}... ` : tag} </Tag> ); return isLongTag ? <Tooltip key={tag} title={tag}>{tagElem}</Tooltip> : tagElem; })} {inputVisible && ( <Input className={style.tagStyle} ref={this.saveInputRef} type="text" size="small" style={{ width: 108 }} value={inputValue} onChange={this.handleInputChange} onBlur={this.handleInputConfirm} onPressEnter={this.handleInputConfirm} /> )} {! inputVisible && <Button className={style.tagStyle} size="small" type="dashed" onClick={this.showInput}>+ New Tag</Button>} </div> ) } componentDidMount() { this.props.getAllTags(); } } function mapStateToProps(state) { return{ tags:state.admin.tags } } function mapDispatchToProps(dispatch) { return{ getAllTags : bindActionCreators(get_all_tags,dispatch), deleteTag : bindActionCreators(delete_tag,dispatch), addTag : bindActionCreators(add_tag,dispatch), } } export default connect( mapStateToProps, mapDispatchToProps )(AdminManagerTags)Copy the code

Saga’s treatment:

export function* delTag(name) { yield put({type: IndexActionTypes.FETCH_START}); try { return yield call(get, `/admin/tags/delTag? name=${name}`); } catch (err) {yield put({type: indexactiontypes.set_message, msgContent: 'Network request error ', msgType: 0}); } finally { yield put({type: IndexActionTypes.FETCH_END}) } } ... . export function* delTagFlow() { while (true){ let req = yield take(ManagerTagsTypes.DELETE_TAG); let res = yield call(delTag,req.name); if (res.code === 0) { yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 1}); yield put({type:ManagerTagsTypes.GET_ALL_TAGS}); } else if (res.message === 'id has expired, please log in again ') {yield put({type: indexactiontypes.set_message, msgContent: res.message, msgType: 0}); setTimeout(function () { location.replace('/'); }, 1000); } else { yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 0}); }}}Copy the code

The operation is the same as before, but it is important to note that there is an extra layer of information returned to determine whether the user information is out of date and is processed in saga.

conclusion

At this point, label management is basically done. The Link or history.push of the front page route will not be explained here. You can look at the code a little bit more.

In the next article we will carry out the operation of the article. Document, add, delete, change and check functions.

Project implementation steps series blog

  • React Stack + Express front and back end blog project (0) — warm up a wave
  • React Technology stack + Express Front and back end blog project (1) — overall project structure building, state state tree design
  • React Stack + Express Front-end blog project (2) — React-XXX front-end, routing configuration
  • React Stack + Express Front and back end blog project (3) – Back-end routing, proxy, static resource hosting and other configuration instructions
  • React Technology Stack + Express Front-end and back-end blog project (4) — blog homepage code writing and redux-Saga organization
  • React Technology Stack + Express Front and back end Blog Project (5) — The front and back end implements the login function
  • React Technology stack + Express Front and back end blog project (6) — Use session to achieve login free + management background permission verification
  • React Technology Stack + Express Front-end and back-end blog Project (7) — User view function of front-end management interface + corresponding back-end interface development
  • React Technology Stack + Express Front-end and back-end blog Project (8) — label management function of front-end management interface + corresponding back-end interface development
  • React Technology Stack + Express Front-end blog Project (9) — Comments management function of front-end management interface + corresponding back-end interface development
  • React Technology Stack + Express Front and back end blog Project (10) — Publish articles on the front management interface
  • React Stack + Express Front and back end blog project (11) — add, delete, change and check the corresponding article part of the backend interface
  • React Stack + Express Front and back end blog Project (12) — Front end for post part improvement (add, delete, change, check, pagination, etc.)
  • React Stack + Express Front and back end blog Project (13) — The front end for the improvement of the post part (add, delete, change, check, etc.)
  • React Stack + Express Front and back end blog project (14) — display of content details page and number of views
  • React Technology Stack + Express Front and back End Blog Project (15) — Add comment function and corresponding back end implementation for blog
  • React Stack + Express Front and back end blog project (16) — PM2 usage instructions
  • React Stack + Express Front and back End Blog Project (17) — Wrap up

Study and communication

Welcome to pay attention to personal wechat official account: Nealyang full stack front, get the first-hand article push and free full stack ebook sharing benefits