Redux یک کتابخانه مستقل برای مدیریت State ها است که می تواند با هر کتابخانه و فریم ورکی استفاده شود. در صورتی که با React آشنایی داشته باشید، Redux را همراه با React استفاده کرده اید.
کاربرد اصلی Redux این است که می توانیم از یک وضعیت (state) به عنوان state سراسری استفاده کنیم و به آسانی از هر کامپوننت Reactیی به این state سراسری دسترسی داشته باشیم، چه این کامپوننت جزو سلسله مراتب آن باشد یا رابطه والد-فرزند با آن داشته باشد.
1- نصب React Native
2- افزودن Textbox و دکمه به App.js
3-تعریف state و input handler
4- ایجاد فولدرهای مربوطه در روت پروژه
5- ایجاد یک تابع Reducer
6- ایجاد یک Redux Store
7-پاس دادن Store به برنامه React Native
8-اتصال برنامه React Native به Redux Store
کدهای زیر را در ترمینال وارد کنید.
npm install -g react-native-cli
یک برنامه جدید ایجاد کنید
react-native init rncreate cd rncreate
بعد از نصب، برنامه را در هر دو شبیه ساز ios و اندروید باز کنید.
react-native run-ios
درصورتی که XCode را به درستی پیکربندی کرده باشید، باید شبیه ساز ios به درستی باز شود.
با دستور زیر برنامه را در شبیه ساز اندروید اجرا کنید.
react-native run-android
کتابخانه های react-redux و redux را با دستور زیر نصب کنید.
yarn add redux react-redux # or npm install redux react-redux --save
حال یک دکمه و Textbox برای افزودن اسم مکان ها و همچنین لایوت flexbox را اضافه می کنیم. کدهای زیر را در فایل App.js قرار دهید.
// App.js import React, {Component} from 'react'; import { StyleSheet, View, TextInput, Button } from 'react-native'; export default class App extends Component { placeSubmitHandler = () => { console.log("Submitted"); } render() { return ( <View style={ styles.container }> <View style = { styles.inputContainer }> <TextInput placeholder = "Seach Places" style = { styles.placeInput } ></TextInput> <Button title = 'Add' style = { styles.placeButton } onPress = { this.placeSubmitHandler } /> </View> </View> ); } } const styles = StyleSheet.create({ container: { paddingTop: 30, justifyContent: 'flex-start', alignItems: 'center', }, inputContainer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', width: '100%' }, placeInput: { width: '70%' }, placeButton: { width: '30%' }, listContainer: { width: '100%' } });
حال یک state برای مدیریت برنامه ایجاد میکنیم.
// App.js state = { placeName: '', places: [] } placeSubmitHandler = () => { console.log("Submitted"); }
فولدرهای زیر را در روت پروژه ایجاد کنید.
داخل فولدر actions یک فایل به نام type.js اضافه کرده و کدهای زیر را در آن قرار دهید.
export const ADD_PLACE = 'ADD_PLACE'
نوع اکشن از نوع reducer است. بسته به نوع اکشن، reducer مربوطه اجرا می شود و می توانیم state را به این طریق تغییر دهیم.
بنابراین یک کپی از state موجود ایجاد کرده و state جدید را بر می گردانیم.
حال یک فایل دیگر به نام place.js در همان دایرکتوری ایجاد کنید.
// place.js import { ADD_PLACE } from './types'; export const addPlace = placeName => { return { type: ADD_PLACE, payload: placeName } }
تابع addPlace() یک اکشن را بر می گرداند. حال با توجه به نوع اکشن برگشتی میتوانیم تابع reducer مربوطه را اجرا کنیم.
اما ما باید به یک روشی این اکشن را به کامپوننت App.js متصل کنیم، در غیر اینصورت نمی توانیم داده ها را داخل Redux Store اضافه کنیم.
همچنین ابتدا باید یک Store ایجاد کنیم. اما قبل از آن باید یک تابع reducer بوجود بیاوریم. پس ابتدا یک reducer و بعد از آن Store را ایجاد و سپس برنامه React Native را به Redux store متصل می کنیم.
داخل فولدر reducer یک فایل به نام placeReducer.js ایجاد و کدهای زیر را در آن قرار می دهیم.
// placeReducer.js import { ADD_PLACE } from '../actions/types'; const initialState = { placeName: '', places: [] }; const placeReducer = (state = initialState, action) => { switch(action.type) { case ADD_PLACE: return { ...state, places: state.places.concat({ key: Math.random(), value: action.payload }) }; default: return state; } } export default placeReducer;
در کدهای بالا یک تابع به نام placeReducer ایجاد کردیم که دو آرگومان می گیرد:
ابتدا initialState برنامه مان را گرفته و آن را به عنوان آرگومان به PlaceReducer پاس می دهیم و با توجه به نوع اکشن، عملیات مربوطه را اجرا می کنیم. آرگومان دوم برابر action است که شامل type و Payload است. Payload در واقع همان placeName است و مقدار textbox را گرفته و آن را در آرایه placeName وارد می کنیم.
دقت کنید در اینجا ما State جدید را بر میگردانیم نه State جاری. بنابراین ما این state جدید را تغییر می دهیم نه state جاری.
داخل روت پروژه یک فایل به نام Store.js ایجاد و کدهای زیر را در آن قرار می دهیم.
// store.js import { createStore, combineReducers } from 'redux'; import placeReducer from './reducers/placeReducer'; const rootReducer = combineReducers({ places: placeReducer }); const configureStore = () => { return createStore(rootReducer); } export default configureStore;
در کدهای بالا ما یک Redux Store ایجاد کرده و reducer را به Store پاس می دهیم. تابع combineReducer همه reducerهای مختلف را به یک reducer ترکیب می کند و State سراسری را شکل می دهد.
پس این state سراسری برای کل برنامه است.
داخل روت پروژه فایل index.js را پیدا کرده و کدهای زیر را در آن فایل اضافه کنید.
// index.js import { AppRegistry } from 'react-native'; import React from 'react'; import App from './App'; import { name as appName } from './app.json'; import { Provider } from 'react-redux'; import configureStore from './store'; const store = configureStore() const RNRedux = () => ( <Provider store = { store }> <App /> </Provider> ) AppRegistry.registerComponent(appName, () => RNRedux);
این تقریباً مثل برنامه React است و ما provider را به عنوان عنصر ریشه پاس داده و سپس با استفاده از تابع connect() مربوط به کتابخانه react-redux می توانیم هر نوع کامپوننت React را به Redux Store پاس می دهیم.
در انتها کامپوننت App.js را به Redux store پاس می دهیم.برای اینکار به تابع connect() از کتابخانه react-redux نیاز داریم
// App.js import React, { Component } from 'react'; import { StyleSheet, View, TextInput, Button, FlatList } from 'react-native'; import ListItem from './components/ListItem'; import { connect } from 'react-redux'; import { addPlace } from './actions/place'; class App extends Component { state = { placeName: '', places: [] } placeSubmitHandler = () => { if(this.state.placeName.trim() === '') { return; } this.props.add(this.state.placeName); } placeNameChangeHandler = (value) => { this.setState({ placeName: value }); } placesOutput = () => { return ( <FlatList style = { styles.listContainer } data = { this.props.places } keyExtractor={(item, index) => index.toString()} renderItem = { info => ( <ListItem placeName={ info.item.value } /> )} /> ) } render() { return ( <View style={ styles.container }> <View style = { styles.inputContainer }> <TextInput placeholder = "Seach Places" style = { styles.placeInput } value = { this.state.placeName } onChangeText = { this.placeNameChangeHandler } ></TextInput> <Button title = 'Add' style = { styles.placeButton } onPress = { this.placeSubmitHandler } /> </View> <View style = { styles.listContainer }> { this.placesOutput() } </View> </View> ); } } const styles = StyleSheet.create({ container: { paddingTop: 30, justifyContent: 'flex-start', alignItems: 'center', }, inputContainer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', width: '100%' }, placeInput: { width: '70%' }, placeButton: { width: '30%' }, listContainer: { width: '100%' } }); const mapStateToProps = state => { return { places: state.places.places } } const mapDispatchToProps = dispatch => { return { add: (name) => { dispatch(addPlace(name)) } } } export default connect(mapStateToProps, mapDispatchToProps)(App)
در کد بالا، هنگامی که روی دکمه add کلیک کنیم، برنامه مقدار textbox را گرفته و آن را به اکشن ارسال میکند و سپس اکشن یک آبجکت همراه با نوع اکشن و payload را برگردانده و بسته به نوع اکشن، Reducer مربوطه اجرا شده و مقدار آن را به Store اضافه می کند.
حال اگر مقدار store تغییر کرد، باید رابط کاربری برنامه (UI) را بسته به نوع مقادیر جدید، بروزرسانی کنیم که برای اینکار از تابع mapStateToProps را ایجاد کردیم.
سپس هنگامی که places array که همان stateمان است، یک مقدار جدید بگیرد، تابع render() اجرا شده و رابط کاربری برنامه را بروزرسانی می کند.
تابع mapDispatchToProps کمک می کند تا برنامه را به اکشن مورد نیاز متصل کنیم. سپس این اکشن به وسیله reducer اجرا می شود و state برنامه را تغییر می دهد.
همچنین داخل فولدر components یک فایل به نام ListItem.js ایجاد و کدهای زیر را در آن قرار می دهیم.
// ListItem.js import React from 'react'; import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; const ListItem = (props) => { return ( <TouchableOpacity> <View style = { styles.listItem }> <Text>{ props.placeName }</Text> </View> </TouchableOpacity> ); } const styles = StyleSheet.create({ listItem: { width: '100%', padding: 10, marginBottom: 10, backgroundColor: '#eee' } }); export default ListItem;
این کامپوننت پروپرتی ها را از کامپوننت والد گرفته و داده ها را به یک شکل مناسب نمایش می دهد. فایل را ذخیره کنید و نتیجه را در شبیه ساز بینید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.