استفاده از 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.jsimport { 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 counterReducerstore.jsimport { createStore } from 'redux' import reducers from './reducers' export default createStore(reducers)app.jsimport { 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.jsimport 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.jsimport { createContext } from 'react' export const { Provider, Consumer } = createContext({ count: 0, increment: () => {}, decrement: () => {} })app.jsimport 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 Appcounter.jsimport 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 https://twitter.com/dan_abramov/status/964923915448586240 به همین دلیل نمیتونم استناد کنم به حرف هایی که هر لحظه در حال تغییرن .