به نام او
بعد از مدتها نودجیاس این دفعه یکمی بریم سراغ ریاکت که هم از نحوی زندگیشون آگاه بشیم هم یکمی تمرین کنیم .
اول از همه بگم این مقاله امروز به نحوی ترجمه داکیومنت اصلی هستش با یکم تغییرات و ملیسازی دقیقا مثل اندروید ملی
خب بریم سراغ اینکه امروز قراره چیکار کنیم .
یه لیستی داریم از یسری فیلم که خودم از فیلیمو جمعآوری کردم .... قراره اینارو نشون بدیم و بتونیم یه سرچ ساده رو توشون پیادهسازی کنیم .
ساختار دیتاهامون این شکلیه :
{
category: "سریال خارجی",
imageUrl: "URL",
isHd: true,
name: "وقتی اونا ما رو دیدن - قسمت 1"
}
خب پروژه رو استارت میزنیم با create-react-app ... بعدش حالا به طرز تفکر ریاکتی باید توجه کنیم .
الان ما یه Table داریم که میخوایم توش دیتاها رو نشون بدیم و یه بخش سرچ داریم در نتیجه دوتا کامپوننت اصلی داریم .... از طرفی باید باز هم ببنیم آیا امکان این هست که بازم ریز تر بشیم یا نه ...
اگر به دیتا ها نگاه کنیم ما یه جدول باید داشته باشیم، که توی اون جدول باید برحسب دستهبندی جدا کنیم و از طرفی هر کدوم از دیتاهای ما باید یک سطر از جدول باشه، و توی زندگی ریاکتی اینا یعنی بخشهای مجزا ....
خب پس ساختار پروژهمون رو به این شکل میسازیم و فایل های رو ایجاد میکنیم :
src
├── components
│ ├── MovieTable
│ │ ├── MovieCategoryRow.js
│ │ ├── MovieRow.js
│ │ └── MovieTable.js
│ └── SearchBar.js
├── data
│ ├── movies.js
├── FilterableMovieTable.js
├── index.css
├── index.js
└── serviceWorker.js
خب حالا ما میتونیم استارت کار رو بزنیم، برحسب جوری که راحتید میتونید اول از بخشهای ریز مثل MovieRow شروع کنید یا اول اون بخش بزرگ اصلی ها رو بنویسید و بعد بیاید سراغ کوچیکا یا در هم بر هم بنویسید .... اما برای اینکه گم نشیم اول یه کوچولو از بخش بزرگ رو میزنیم و بعد قسمتای کوچیکشو کامل میکنیم.
وارد index.js میشیم . در وهلهی اول کامپوننت بزرگمون رو اضافه میکنیم و به عنوان props بهش لیست دیتاهامون رو پاس میدیم. یعنی میشه به این شکل :
import React from "react";
import ReactDOM from "react-dom";
import FilterableMovieTable from "./FilterableMovieTable";
import MOVIES from "./data/movies";
import "./index.css";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(<FilterableMovieTable movies={MOVIES} />,
document.getElementById("root")
);
serviceWorker.unregister();
خب حالا بریم سراغ نوشتن FilterableMovieTable :
import React from "react";
import SearchBar from "./Components/SearchBar";
import MovieTable from "./Components/MovieTable/MovieTable";
class FilterableMovieTable extends React.Component {
render() {
return (
<div className="container">
<div className="row">
<div className="col-12">
<SearchBar/>
<MovieTable movies={this.props.movies} />
</div>
</div>
</div>
);
}
}
export default FilterableMovieTable;
خب حالا میریم سراغ SerachBar
import React from "react";
function SearchBar() {
return (
<div class="card">
<form className="form-horizontal">
<input
type="text"
placeholder="جستجو ..."
className="form-control"/>
<p>
<input type="checkbox" />{" "}
فقط فیلمهای با کیفیت 720 {" "}
</p>
</form>
</div>
);
}
export default SearchBar;
خب حالا باید یکسری تغییرات ایجاد کنیم تا این بخش ما به یچیز درست درمون شبیه شه، نکته اینجاس ما قراره لیست فیلمها رو تو یه کامپوننت دیگه رندر کنیم از طرفی از بخش سرچ به اون بخش دسترسی نداریم، پس راهکاری که داریم اینه که توی FilterableMovieTable یه state داشته باشیم برای نگهداری محتوایی که قراره سرچش کنیم و لیست فیلمها رو بر اساس اون نمایش بدیم، از طرفی برای تغییر مقدار این state باید به SearchBar دسترسی بدیم .
در نتیجه کدهای ما به این صورت تغییر میکنه :
FilterableMovieTable
class FilterableMovieTable extends React.Component {
constructor(props) {
super(props);
this.state = {
filterText: "",
isHd: false
};
this.handleFilterTextChanged = this.handleFilterTextChanged.bind(this);
this.handleisHdChanged = this.handleisHdChanged.bind(this);
}
handleFilterTextChanged(filterText) {
this.setState({
filterText: filterText
});
}
handleisHdChanged(isHd) {
this.setState({
isHd: isHd
});
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-12">
<SearchBar
filterText={this.state.filterText}
isHd={this.state.isHd}
onFilterTextChanged={this.handleFilterTextChanged}
onisHdChanged={this.handleisHdChanged}/>
<MovieTable movies={this.props.movies}/>
</div>
</div>
</div>
);
}
}
SearchBar
function SearchBar({ filterText, isHd, onFilterTextChanged, onisHdChanged }) {
const handleFilterTextChanged = e => {
onFilterTextChanged(e.target.value);
};
const handleisHdChanged = e => {
onisHdChanged(e.target.checked);
};
return (
<div class="card">
<form className="form-horizontal">
<input
type="text"
placeholder="جستجو ..."
value={filterText}
className="form-control"
={handleFilterTextChanged}/>
<p>
<input type="checkbox" checked={isHd} ={handleisHdChanged} />{" "}
فقط فیلمهای با کیفیت 720 {" "}
</p>
</form>
</div>
);
}
خب تمام ..... این بخش تموم شد .... حالا باید وارد ریزه کاریای نمایش جدول داده هامون بشیم ....
اول بخش های کوچیکشون رو بنویسیم MovieCategoryRow :
import React from "react";
function MovieCategoryRow({ category }) {
return (
<tr >
<th colSpan="3">
{category}
</th>
</tr>
);
}
export default MovieCategoryRow;
بعدشم که هر سطر از جدول رو بنویسیم :
import React from "react";
function MovieRow({ movie }) {
const hdTagClass = movie.isHd ? "info" : "dark";
const hdTagText = movie.isHd ? "720p" : "1080p";
return (
<tr>
<td>
<span className={"badge badge-" + hdTagClass}>{hdTagText}</span>
</td>
<td>{movie.name}</td>
<td>
<img
className="img"
src={movie.imageUrl}
alt={movie.name}
height="100"/>
</td>
</tr>
);
}
export default MovieRow;
خب قبل از اینکه کد رو ادامه بدم یه نکته کوچولوی آموزشی ? بگم که خیلی خوبه و میتونید ازش استفاده کنید
ببینید زمانی که میخواهید یه تمایزی بین ظاهر قائل بشید باید className رو تغییراتی بدین و اونو برحسب دادهاتون مرتب کنید از طرفی یکسری ها ثابت هستن برای اینکه بتونید به طور خفن طور مدیریت کنید
میتونید به این شکل عمل کنید که :
const hdTagClass = movie.isHd ? "info" : "dark";
و زمان استفاده اینجوری استفادش کنید که :
<span className={"badge badge-" + hdTagClass}>محتوای مضخرف فرزاد</span>
خیلی خوبه این روش ....
خب دگ وارد مراحل اخر کار میشیم :
خب برای اینکه بتونیم لیستمون رو برحسب اون مقادیر داخل کادر جستجومون بچینیم لازمه که یک تغییراتی توی FilterableMovieTable بدیم که توی این کامپوننت هم به مقدار کادر جستجومون دسترسی داشته باشیم
<MovieTable
movies={this.props.movies}
filterText={this.state.filterText}
isHd={this.state.isHd}
/>
خب حالا وارد کدای MovieTable میشیم و مینویسم اونارو .... کدا واضح هستن اما اگه جایی ابهامی بود تو کامنت ها بپرسید،
import React from "react";
import MovieCategoryRow from "./MovieCategoryRow";
import MovieRow from "./MovieRow";
function MovieTable({ movies, filterText, isHd }) {
const rows = [];
let lastCategory = null;
movies.forEach(movie => {
if (movie.name.indexOf(filterText) === -1) {
return;
}
if (isHd && !movie.isHd) {
return;
}
if (movie.category !== lastCategory) {
rows.push(
<MovieCategoryRow category={movie.category} key={movie.category} />
);
}
rows.push(<MovieRow movie={movie} key={movie.name} />);
lastCategory = movie.category;
});
return (
<div class="card">
<table className="table table-image">
<thead>
<tr>
<th scope="col">کیفیت</th>
<th scope="col">نام</th>
<th scope="col">#</th>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
</div>
);
}
export default MovieTable;
و تامام
پینوشت:
میتونید بوت استرپ و فونت وزیر رو وارد کار کنید که یکم پروژه رنگ و لعاب بگیره ....
لینک داکیومنت اصلی (البته اینجا با کلاس نوشته و من فانکشن ها)

