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!

Results demonstrate

  • Results show

  • Database Screenshot

Back-end partial implementation

Article content initially contains the following fields: article title, article content, author, article tag, number of views, number of comments, publication time, whether to publish

So define the schema as follows:

Import mongoose from 'mongoose' module.exports = new mongoose.Schema({title:String,// ViewCount :Number,// commentCount:Number,// commentCount:Number,// commentCount time:String,// published time coverImg:String,// Cover image author:String,// Author Tags :Array,// tags isPublish:Boolean// Whether publish});Copy the code

Backend post interface development is actually a storage interface, preliminary interface design for/API/admin/article/addArticle

router.post('/addArticle', function (req, res) { const { title, content, time, tags, isPublish } = req.body; const author = req.session.userInfo.username; const coverImg = `/${Math.round(Math.random() * 9 + 1)}.jpg`; const viewCount = 0; const commentCount = 0; let tempArticle = new Article({ title, content, isPublish, viewCount, commentCount, time, author, coverImg, tags }); Temparticle.save ().then(data=>{responseClient(res,200,0,' saved successfully ',data)}).cancel(err=>{console.log(err); responseClient(res); }); });Copy the code

The back end is more general. For routing design and model we can view the source code

The front part

Interface coding:

Render () {return (<div> <h2> post </h2> <div className={style.container}> <span className={style.subtitle}> title </span> <Input className={style.titleInput} placeholder={type='text' value={this.props. Title} OnChange ={this.titleonchange.bind (this)}/> <span className={style.subtitle}> </span> <textarea className={style.textArea} value={this.props.content} onChange={this.onChanges.bind(this)}/> <span ClassName ={style.titleInput} placeholder= {className={style.titleInput} placeholder= {className={style.titleInput} placeholder= { onChange={this.selectTags.bind(this)} defaultValue={this.props.tags} > { this.props.tagsBase.map((item) => { return ( <Option key={item}>{item}</Option> ) }) } </Select> <div className={style.bottomContainer}> <Button type="primary" OnClick ={this.publisharticle.bind (this)} className={style.buttonstyle}> </Button> <Button type="primary" OnClick ={this.savearticle.bind (this)} className={style.buttonstyle}> Save </Button> <Button type="primary" OnClick ={this.preview.bind (this)} className={style.buttonstyle}> preView </Button> </div> </div> <Modal OnOk ={this.handleok.bind (this)} width={'900px'} onCancel={this.handleOk.bind(this)} footer={null} > <div className={style.modalContainer}> <div id='preview' className={style.testCode}> {remark().use(reactRenderer).processSync(this.props.content).contents} </div> </div> </Modal> </div> ) }Copy the code

Defined as a technical blog, we only support the MD syntax here. Use remark-react to convert the MD syntax. TextArea as input field. There is currently no support for uploading images. If you want to support image uploads, check out my other demo on Github. I’m not going to do the demo here.

State design of the front part

For the post part, I store title,tags and content separately. To make it easier for users to switch to other menu items when writing general articles. So store it in state. Update state directly when typing title,content,tags in input. This way, when the user switches to another TAB and back, the user can still see what he entered.

const initialState={ title:'', content:'', tags:[] }; export const actionTypes = { UPDATING_TITLE:"UPDATING_TITLE", UPDATING_CONTENT:"UPDATING_CONTENT", UPDATING_TAGS:"UPDATING_TAGS", SAVE_ARTICLE:"SAVE_ARTICLE" }; export const actions = { update_title:function (title) { return{ type:actionTypes.UPDATING_TITLE, title } }, update_content:function (content) { return{ type:actionTypes.UPDATING_CONTENT, content } }, update_tags:function (tags) { return{ type:actionTypes.UPDATING_TAGS, tags } }, save_article:function (data) { return{ type:actionTypes.SAVE_ARTICLE, data } } }; export function reducer(state=initialState,action) { switch (action.type){ case actionTypes.UPDATING_TITLE: return{ ... state,title:action.title }; case actionTypes.UPDATING_CONTENT: return{ ... state,content:action.content }; case actionTypes.UPDATING_TAGS: return{ ... state,tags:action.tags }; default: return state; }}Copy the code

Front-end Saga

In Saga, we need to determine whether the user should save or publish. So we added the isPublish field to differentiate. There are some required fields that we need to judge when publishing.

export function* saveArticleFlow () { while (true){ let request = yield take(NewArticleActionTypes.SAVE_ARTICLE); console.log(request); if(request.data.isPublish){ if(request.data.title === ''){ yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: 'Please enter article title ', msgType: 0}); }else if(request.data.content === ""){yield put({type: indexactiontypes.set_message, msgContent: 'Please enter the content of the article ', msgContent: 0}); }else if(request.data.tags.length === 0){ yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: 'Please select article category ', msgType: 0}); } } if((request.data.title&&request.data.content&&request.data.tags.length>0&&request.data.isPublish)|| (! request.data.isPublish)){ let res = yield call(saveArticle,request.data); if(res){ if (res.code === 0) { yield put({type: IndexActionTypes.SET_MESSAGE, msgContent: res.message, msgType: 1}); setTimeout(function () { location.replace('/admin/managerArticle'); }, 1000); } 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

When the article is published successfully, we will jump to the article management interface after a given second. Since the management interface is not developed at present, it will be 404 after jumping to the management interface. In the next article, we’ll cover feature development for the article administration section.

The article preview

The preview of the article, directly use ANTD modal, and then convert MD syntax, show the effect.

conclusion

Generally speaking, the article is also relatively simple to publish. I want you to think about the details. At this point, the core function of a blog site is complete.

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 and back-end blog project (9) — Post function on the front-end management interface + corresponding back-end interface
  • React Technology Stack + Express Front-end and back-end blog Project (10) — Comments management function of front-end management interface + corresponding back-end interface development
  • 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