در این آموزش قصد داریم اتصال به React و Redux را توضیح بدهیم.
در این مثال از کدهای back-end استفاده نمی کنیم. ما سعی می کنیم این مثال را خیلی ساده انجام بدهیم و آن را در سمت کلاینت اجرا خواهیم کرد. در ابتدا یک پست ساده ایجاد کرده و آن را نمایش می دهیم، اما قصد داریم ذخیره پست ها را با Redux مدیریت کنیم. همچنین می توانیم با این آموزش پست هایمان را ایجاد و حذف و ذخیره کنیم. برای بخش frontend از بوت استرپ 4 استفاده می کنیم.
در صورتی که با Redux آشنایی ندارید، ابتدا مقاله آموزش Redux از پایه را مطالعه بفرمایید.
1- نصب React.js
2-نصب Redux و react-redux
3- ایجاد کامپوننت NewPost
4- ایجاد اکشن ها
5- ایجاد rootReducer و postReducer
6- پیکربندی ذخیره (store)
7- ایجاد کامپوننت container
8- نمایش پست ها
APIیی که برای اتصال React و Redux استفاده می شوند خیلی ساده است: یک کامپوننت Provider که باعث می شود مطالب ذخیره شده در برنامه ما قابل دسترسی باشد و یک تابع connect که یک کامپوننت container ایجاد می کند که می تواند state ها را از Store بخواند و اقداماتی را روی آن انجام دهد.
در اینجا ما آخرین نسخه React را نصب میکنیم.
دستورات زیر را بنویسید.
npm install -g create-react-app create-react-app postreactredux
دستورات زیر را برای نصب هر دو مورد در ترمینال وارد کنید:
npm install redux react-redux --save # or yarn add redux react-redux
با دستور زیر بوت استرپ 4 را نصب کنید.
npm install bootstrap --save
حال این فایل (بوت استرپ 4) را داخل فایل src > index.js ، import کنید.
// index.js import '../node_modules/bootstrap/dist/css/bootstrap.min.css'
اگر از React و Redux با هم استفاده کنید، یک تفکیک بین برنامه ها وجود خواهد داشت. یعنی دو نوع از کامپوننت ها وجود دارد.
1- کامپوننت های Dumb (غیرهوشمند)
2- کامپوننت های Smart (هوشمند) - کانتینرها
کامپوننت های Dumb داده ها را رندر می کنند، اما آنها هیچ اطلاعی از منطق آنها ندارند.
کامپوننت های Smart درباره منطق اطلاع دارند و به طور مستقیم به Store متصل می شود.
حالا، داخل ولدر src یک فایل به نام NewPost.js ایجاد کنید.
// NewPost.js import React from 'react'; class NewPost extends React.Component { state = { title: '', body: '' }; handleInputChange = e => { this.setState({ [e.target.name]: e.target.value }); }; handleSubmit = e => { e.preventDefault(); if (this.state.title.trim() && this.state.body.trim()) { console.log(this.state); this.handleReset(); } }; handleReset = () => { this.setState({ title: '', body: '' }); }; render() { return ( <div> <form onSubmit={ this.handleSubmit }> <div className="form-group"> <input type="text" placeholder="Title" className="form-control" name="title" onChange={ this.handleInputChange } value={ this.state.title } /> </div> <div className="form-group"> <textarea cols="19" rows="8" placeholder="Body" className="form-control" name="body" onChange={ this.handleInputChange } value={ this.state.body }> </textarea> </div> <div className="form-group"> <button type="submit" className="btn btn-primary">Add Post</button> <button type="button" className="btn btn-warning" onClick={ this.handleReset }> Reset </button> </div> </form> </div> ); } } export default NewPost;
این کامپوننت دو فیلد فرم دارد:
زمانیکه کاربر فرم را ارسال میکند ، می توانیم مقدار دو فیلد را در کنسول ببینیم.
حالا باید فایل NewPost.js را داخل فایل src > App.js وارد (import) کنیم.
// App.js import React, { Component } from 'react'; import NewPost from './components/NewPost'; import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; class App extends Component { render() { return ( <div className="container"> <div className="row"> <div className="col-md-6"> <NewPost /> </div> <div className="col-md-6"> Display Post </div> </div> </div> ); } } export default App;
فایل را ذخیره کرده و سرور توسعه را راه اندازی کنید.
حال ، داخل فولدر src سه فولدر جدید ایجاد کنید و نامگذاری آنها را مطابق زیر انجام دهید.
حال، داخل فولدر actions یک فایل با نام types.js ایجاد کرده و کدهای زیر را در آن قرار دهید:
// types.js export const ADD_POST = 'ADD_POST'; export const DELETE_POST = 'DELETE_POST';
اینها نوع اکشن های ما هستند. هنگامی که کاربری فرم را ارسال (submit) کند، ما باید این اکشن ها را فراخوانی کنیم. و هنگامی که کاربر یک پست را ایجاد میکند، ما باید اکشن ADD_POST را فراخوانی کنیم. این اکشن توابع reducer را فراخوانی می کند و مقادیر را به Store ارسال میکند.
پس ما مستقیما نمی توانیم store را تغییر بدهیم، بلکه باید یک اکشن درست کنیم و سپس تابع reducer را فراخوانی کرده تا وضعیت Store را تغییر دهد.
برای delete هم به این صورت است، هنگامی که ما سعی می کنیم پستی را حذف کنیم، اکشن DELETE_POST اتفاق می افتد. حالا، این اکشن یک آبجت بر می گرداند که شامل دو پروپرتی است.
همان طور که در مثال دیدید ما دو اکشن داریم، پس یک فایل دیگر داخل فولدر src > actions به نام index.js ایجاد می کنیم.
اما قبل از آن، باید به هر پست یک شناسه (id) منحصر به فردی بدهیم، پس برای تولید id در سمت کلاینت، از کتابخانه npm به نام uuid استفاده می کنیم.
npm install uuid --save # or yarn add uuid
حال کدهای زیر را در فایل src > actions > index.js قرار دهید.
// actions >> index.js import uuidv4 from 'uuid/v4'; import { ADD_POST, DELETE_POST } from './types'; export const createPost = ({ title, body }) => ({ type: ADD_POST, payload: { id: uuidv4(), title, body } }); export const deletePost = id => ({ type: DELETE_POST, payload: { id } });
تابع createPost، title و body را به عنوان یک پارامتر دریافت میکند و یک آبجکت را بر میگرداند.
همچنین یک payload دیگر به نام id ایجاد میکنیم که با آن می توانیم پست های مختلف را رندر کرده و آنها را از روی id شان حذف کنیم.
حال داخل فولدر reducers یک فایل با نام postReducer.js اضافه کنید.
// postReducer.js import { ADD_POST, DELETE_POST } from '../actions/types'; export default function postReducer(state = [], action) { switch (action.type) { case ADD_POST: return [...state, action.payload]; case DELETE_POST: return state.filter(post => post.id !== action.payload.id); default: return state; } }
اگر این نوع اکشن با نوع اکشن اتفاق افتاده مطابقت کند، می تواند store را اصلاح (modify) کند و وضعیت کنونی آن را تغییر دهد.
حال یک فایل با نام index.js داخل فولدر resurces ایجاد کرده و کدهای زیر را در آن قرار دهید.
// index.js import { combineReducers } from 'redux'; import posts from './postReducer'; export default combineReducers({ posts: posts });
فایل index.js را داخل مسیر src > index.js وارد(import) کنید.
به این ترتیب فایل نهایی src > index.jd باید مطابق زیر باشد.
// src >> index.js import React from 'react'; import ReactDOM from 'react-dom'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import App from './App'; import rootReducer from './reducers'; import registerServiceWorker from './registerServiceWorker'; const store = createStore(rootReducer); ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root')); registerServiceWorker();
داخل فولدر containers یک کامپوننت به نام CreatePost.js ایجاد کنید.
// CreatePost.js import { connect } from 'react-redux'; import { createPost } from '../actions'; import NewPost from '../components/NewPost'; const mapDispatchToProps = dispatch => { return { onAddPost: post => { dispatch(createPost(post)); } }; }; export default connect( null, mapDispatchToProps )(NewPost);
در اینجا کامپوننت NewPost را به Redux Store متصل کردیم.
حال فایل CreatePost.js را داخل فایل src > App.js وارد (import) می کنیم.
// src >> App.js import React, { Component } from 'react'; import CreatePost from './containers/CreatePost'; import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; const stylesApp = { marginTop: 40 } class App extends Component { render() { return ( <div className="container"> <div className="row" style={ stylesApp }> <div className="col-md-6"> <CreatePost /> </div> <div className="col-md-6"> Display Post </div> </div> </div> ); } } export default App;
حال هنگامی که کاربر فرم را ارسال میکند، میتوانیم این اکشن را اجرا کنیم، و این اکشن Reducer را فراخوانی کرده و وضعیت سراسری آن را تغییر می دهد.
حال می توانیم داخل فایل NewPost.js به این اکشن دسترسی داشته باشیم.
// NewPost.js handleSubmit = e => { e.preventDefault(); if (this.state.title.trim() && this.state.body.trim()) { this.props.onAddPost(this.state); this.handleReset(); } };
حال می توانیم وضعیتش را داخل store پیگیری کرده و وضعیتش را با اکشن ها تغییر دهید.
یک کامپوننت داخل فولدر components ایجاد کنید و نام آن را Post.js بگذارید و کدهای زیر را در آن قرار دهید.
کامپوننت Post.js مسئول رندر همه پست ها است.
// Post.js import React from 'react'; const styles = { borderBottom: '2px solid #eee', background: '#fafafa', margin: '.75rem auto', padding: '.6rem 1rem', maxWidth: '500px', borderRadius: '7px' }; export default ({ post: { title, body, id }, onDelete }) => { return ( <div style={ styles }> <h2>{ title }</h2> <p>{ body }</p> <button className="btn btn-danger" type="button" onClick={() => onDelete(id)}> Remove </button> </div> ); };
این کامپوننت تنها داده های عنوان ، محتوا و شناسه پست را گرفته و آن را رندر میکند
همچنین تابع onDelete() را گرفته و اکشن delete را اجرا می کند و این اکشن تابع postReducer را فراخوانی کرده و پست ها را حذف و وضعیت و UI برنامه را بروز رسانی میکند.
حال داخل فولدر containers یک کامپوننت به نام PostList.js ایجاد کنید و کدهای آن را در آن قرار دهید.
// PostList.js import React from 'react'; import { connect } from 'react-redux'; import Post from '../components/Post'; import { deletePost } from '../actions'; function PostList({ posts, onDelete }) { return ( <div> {posts.map(post => { return ( <Post post={ post } onDelete={ onDelete } key={ post.id } /> ); })} </div> ); } const mapStateToProps = state => { return { posts: state.posts }; }; const mapDispatchToProps = dispatch => { return { onDelete: id => { dispatch(deletePost(id)); } }; }; export default connect( mapStateToProps, mapDispatchToProps )(PostList);
حال این کامپوننت آخرین وضعیت (state) را از store می گیرد. وقتی که پست جدیدی اضافه شد این کامپوننت از ان مطلع می شود چون بطور مستقیم به store متصل است. از طرفی اگر اکشن delete اتفاق افتاد، پست ها فیلتر شده و پست های باقی مانده را نمایش می دهد.
حال در انتها باید کامپوننت PostList.js را داخل فایل src > App.js وارد (import) کنیم.
// src >> App.js import React, { Component } from 'react'; import CreatePost from './containers/CreatePost'; import PostList from './containers/PostList'; import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; const stylesApp = { marginTop: 40 } class App extends Component { render() { return ( <div className="container"> <div className="row" style={ stylesApp }> <div className="col-md-6"> <CreatePost /> </div> <div className="col-md-6"> <PostList /> </div> </div> </div> ); } } export default App;
فایل را ذخیره کرده و به آدرس http://localhost:3000/ بروید.
اگر همه چیز به درستی پیکربندی شده باشد، می توانیم پست هایمان را اضافه، حذف، و آنها را نمایش بدهیم.
کدهای این مقاله آموزشی را در این آدرس قرار داده ام که در صورت تمایل می توانید آن را دانلود کنید.
برای استفاده از کدهایی که درگیت هاپ قرار داده ام مراحل زیر را انجام دهید:
1-از ریپازیتوری clone بگیرید
2- به فولدر پروژه رفته و دستور npm install را برای نصب وابستگی ها ،اجرا کنید.
3- سرور توسعه را با دستور yarn start راه اندازی کنید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.