یه برنامه نویس معمولی لینوکس کار
استفاده از context api یا Redux (به دور از تعصب)
کسایی که منو میشناسن ، میدونن که روی context api خیلی متعصبم ( تعصب بی جا ) . دلیلش هم داشتن یک سری استاندارد ها و یک سری امکانات خوبه که کار رو راحت میکنه .
تقریبا میشه گفت دو ساله با ریداکس آشنا هستم . ( چون سخته بگی به چی تسلط داری یا نداری . نمیتونم بگم تسلط دارم . اونایی که میگن به فلان چیز تسلط صد در صد دارن خیلی شجاعن ) .
با حرف عامر لطفی خیلی موافقم ( برنامه نویس شیپور ) ، همه اینا فقط ابزار هستن و باید بدونیم از کدوم کجا استفاده کنیم .
در نهایت واقعا همینه .
اما منم یک سری تعصبات بی جا روی سیستم عامل ، ابزار ، لایبرری و... دارم که دوست دارم در موردشون بنویسم و بخونم .
ریداکس چیه؟
A predictable state container for JavaScript apps.
یک قالب برای بررسی تغییرات state ها داخل اپلیکیشن های جاوا اسکریپتی . ( موبایل ، وب و ... ) که خیلی منعطف و قوی هست و Dan abramov نویسنده این لایبرری بود . کسایی که Dan Abramov رو میشناسن ، حرفش رو حرف حق میدونن و سند . یعنی میگن دیگه هرچی ایشون بگه همونه . اما به دید من اینطور نیست . خیلی قوی تر از ایشون هم هست که به علت شناخته نشدنشون ، حرفشون خونده نمیشه .
داخل ایران هم هستن افرادی که واقعا کارشون درسته و از ایشون قوی ترن . باید ببینیم هرکس در مورد چیزی که میگه ، چه دیدگاهی داره . شاید Dan Abramov به علت سخنرانی هایی که در مورد ریداکس میکنه ، مایل نیست که بگه context جایگزینی برای redux هست . ( یا نیست ) . پس باید خودمون تحقیق کنیم .
ریداکس اوایل خیلی سنگین بود و کار باهاش واقعا اذیت میکرد . اما به مرور هم کار باهاش توجیه شد هم راه های نوشتنش آسونتر .
اما واقعا راحتی کار رو نمیشه با context قیاس کرد .
نمیخوام بگم چه شکلی کد بنویسیم . فقط دو مثال میزنم و ادامه بحث
نمونه کد :
Action.js
// Action Types
export const COUNTER_INCREMENT = 'COUNTER_INCREMENT'
export const COUNTER_DECREMENT = 'COUNTER_DECREMENT'
// Action Creators
export function incrementCounter () {
return {
type: COUNTER_INCREMENT
}
}
export function decrementCounter () {
return {
type: COUNTER_DECREMENT
}
}
Reducer.js
import {
COUNTER_INCREMENT,
COUNTER_DECREMENT
} from './actions'
const counterInitialState = {
count: 0
}
function counterReducer (state = counterInitialState, action) {
switch (action.type) {
case COUNTER_INCREMENT:
return Object.assign({}, state, { count: ++state.count })
case COUNTER_DECREMENT:
return Object.assign({}, state, { count: --state.count })
default:
return state
}
}
export default counterReducer
store.js
import { createStore } from 'redux'
import reducers from './reducers'
export default createStore(reducers)
app.js
import { Provider } from 'react-redux'
import store from './store'
import Counter from './counter'
class App extends Component {
render() {
return (
<Provider store={store}>
<div className="app">
Redux Example
<Counter />
</div>
</Provider>
)
}
}
counter.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import {
incrementCounter,
decrementCounter
} from './actions'
const mapDispatchToProps = dispatch => ({
increment: () => dispatch(incrementCounter()),
decrement: () => dispatch(decrementCounter())
})
const mapStateToProps = state => ({
counter: state.count
})
class Counter extends Component {
render () {
return (
<div className="counter">
Counter: <span>{this.props.counter}</span>
<div>
<button ={ this.props.decrement }>-</button>
<button ={ this.props.increment }>+</button>
</div>
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Counter)
الان که پروژه ران بشه ، یک counter داریم که شمارش از 1 شروع میشه به بالا .
حالا میخوام همین پروژه رو تغییر بدم به context api . اتفاقاتی که میفته کمی جالب میشه . همین کامپوننت ها رو تغییر میدم و پروژه رو به context تبدیل میکنم .
مثال دوم :
ایجاد فایل context.js
import { createContext } from 'react'
export const { Provider, Consumer } = createContext({
count: 0,
increment: () => {},
decrement: () => {}
})
app.js
import React, { Component } from 'react'
import Counter from './counter'
import { Provider as CounterProvider } from './context.js'
import './app.css'
class App extends Component {
state = {
count: 0,
increment: () => { this.setState({count: this.state.count + 1}) },
decrement: () => { this.setState({count: this.state.count - 1}) }
}
render() {
return (
<CounterProvider value={this.state}>
<div className="app">
Redux Example
<Counter />
</div>
</CounterProvider>
)
}
}
export default App
counter.js
import React, { Component } from 'react'
import { Consumer as CounterConsumer } from './context'
class Counter extends Component {
render () {
return (
<CounterConsumer>
{
({count, increment, decrement}) => (
<div className="counter">
Counter: <span>{ count }</span>
<div>
<button ={ decrement }>-</button>
<button ={ increment }>+</button>
</div>
</div>
)
}
</CounterConsumer>
)
}
}
export default Counter
خوب ، تمام .
تغییراتی که اتفاق افتاد حذف reducer , actions و store بود .
حذف تابع connect هم به عنوان یک HOC که هر بار در رندر شدن کامپوننت ، تاثیر میزاره .
البته این از دید سادگی context نسبت به redux بود .
دیدگاه فنی :
دیدگاهی که مینویسم ، دیدگاه مین نیست. بلکه یک دیدگاه کلی نسبت به دو سیستم هست .
پرفورمنس context نسبت به ریداکس به علت استفاده از
memoized تا حد قابل توجهی بهتر . ریداکس با استفاده از mapStateToProps یک روند رو داخل connect تکرار میکنه . یعنی اگر کامپوننت ۱۰۰ مربته کال بشه ، روند map ۱۰۰ مربته انجام میشه و در نهایت به جایگاه قبل برمیگرده .
این جواب رو داخل لینک زیر دیدم که خالی از لطف نیست :
https://www.reddit.com/r/reactjs/comments/a5sddz/redux_vs_context_api_performance/
موارد بعدی که میشه بین این دو سیستم مقایسه کرد ،استفاده در حجم اپلیکیشن های بالاست . paypal خیلی از استفاده ریداکس راضی هست اما ریسک انتقال رو به کانتکست انجام نداد .
در واقع هنوز سایت پر مخاطبی با context نوشته نشده . ( یا هوز بروز ندادن ) . به همین دلیل نمیشه روی سایت های بزرگ این ادعا رو داشت که بهتره یا نه . در واقع پرفورمنس با مقیاس کوچک ، خیلی بهتره ، اما این امکان هم هست که در مقیاس بالا این حرف درست نباشه .
امکاناتی مثل redux thunk باعث شده که ریداکس محبوبیت هایی داشته باشه که داخل context دیده نمیشه . این امکانات جانبی ریداکس رو از کانتکست برتر کرده .
البته هنوز منتظر تغییرات اساسی context برای ورژن 16.8 به بالا هستیم . تا الان لیست تغییراتی که اعلام شده ، در مورد context api چیزی نگفته .
صحبت های Dan Abramov
حالا چرا من با حرف های ایشون مخالفم؟
داخل توییتی که انجام دادن ، گفتن که:
Most apps that use Redux today probably don’t need it. But I’m glad to hear success stories about cases where Redux-like architecture ends up being actually useful.
اما داخل همون توییت در جواب نوشتن :
Context is what powers React Redux under the hood. The new context API isn’t to “replace Redux”, it just fixes a broken feature that needs to be provided by React. Whether you use it directly or through another API like RR is up to you
به همین دلیل نمیتونم استناد کنم به حرف هایی که هر لحظه در حال تغییرن .
مطلبی دیگر از این انتشارات
پیشنیازهای لازم برای یادگیری React و React-Native
مطلبی دیگر از این انتشارات
SSR: پایان کابوس بارگذاری صفحات خالی از محتوا در React ،Vue.js و AngularJS
مطلبی دیگر از این انتشارات
بیاین بهتر React Native بنویسیم (قسمت اول)