ไม่กี่ปีที่ผ่านมาเพื่อนร่วมงานคนหนึ่งของฉันบอกฉันเกี่ยวกับ React Native ผมสงสัยมาก ฉันแย้งว่ามันเป็นเพียงกรอบงานข้ามแพลตฟอร์มอีกแบบหนึ่งซึ่งจะไม่มีทางใช้งานได้ในชีวิตจริง - ฉันไม่รู้ว่าตัวเองผิดแค่ไหน
ประเภทของผลตอบแทนจากการลงทุน
หลายปีผ่านไปและทักษะ React Native เป็นที่ต้องการอย่างมาก เนื่องจากเป็นช่วงที่ฉันได้เรียนรู้สิ่งใหม่ ๆ ฉันจึงคิดว่าทำไมไม่ลองดูล่ะ วันนี้ฉันเป็นผู้สนับสนุน React Native ที่ยิ่งใหญ่
จุดด้อย:
ข้อดี:
ฉันสามารถดำเนินการต่อไปได้ แต่ขอหยุดตรงนี้และไปยังหัวข้อของบล็อกโพสต์นี้ ในโพสต์นี้ฉันจะสร้างแอป Android ที่ขับเคลื่อนด้วย React Native สี่แอป:
ดังที่ฉันได้กล่าวไว้ข้างต้นไม่มีวิธีใดที่เราจะใช้ Android Studio สำหรับการพัฒนา React Native ได้ เราต้องการสิ่งทดแทน React Native สามารถพัฒนาได้ในโปรแกรมแก้ไขข้อความสมัยใหม่ที่มีอยู่ (Atom, VS Code, Sublime Text, Brackets ฯลฯ ) แต่เนื่องจากเรามาพร้อมกับประสบการณ์ Android Studio ที่ฉันชอบคือ WebStorm ซึ่งสร้างโดย บริษัท เดียวกัน แม้ว่า WebStorm จะเป็นแอปพลิเคชันแบบชำระเงิน (129 $ ต่อปี) คุณสามารถติดตั้งเวอร์ชันระหว่างการพัฒนาได้ การสร้าง EAP ของ WebStorm นั้นไม่มีค่าใช้จ่ายและค่อนข้างเสถียร หากคุณต้องการโปรแกรมแก้ไขที่ใช้ VS Code ได้ฟรี Microsoft ได้พัฒนาปลั๊กอิน React Native ที่น่าทึ่งสำหรับมันและทำงานได้ดีมาก
ข้อกำหนดเบื้องต้น: Android SDK, Node และ React Native ที่ติดตั้งบนคอมพิวเตอร์ของคุณ
มีสองวิธีในการสร้างโครงการ React Native ใหม่
react-native init AwesomeApeeScapeProject
create-react-native-app AwesomeApeeScapeProject
หากคุณใช้ create-react-native-app
โปรเจ็กต์ที่สร้างขึ้นจะถูกบูตด้วยงานเอ็กซ์โป ฉันจะไม่ลงรายละเอียด แต่โดยพื้นฐานแล้วหมายความว่าคุณไม่จำเป็นต้องติดตั้ง Xcode เพื่อเรียกใช้แอปบน iOS นอกจากนี้ยังง่ายกว่าที่จะให้ลูกค้าได้รับข้อมูลล่าสุดอยู่เสมอผ่านฟังก์ชันการทำงานของ expo.io และคุณสมบัติอื่น ๆ แต่คุณไม่สามารถเพิ่มโค้ดเนทีฟได้ ดังนั้นหากคุณกำลังพัฒนาคุณลักษณะเฉพาะคุณอาจต้องนำแอปออกจากงานแสดงสินค้าและใช้โครงการ React Native ปกติแทน
ฉันจะใช้วิธีแรก
มาดำเนินโครงการกัน ขั้นแรกให้เปิดโปรแกรมจำลองหรือเชื่อมต่ออุปกรณ์ หากคุณสร้างโปรเจ็กต์ด้วย WebStorm GUI สิ่งที่คุณต้องทำก็คือเลือกการกำหนดค่า ที่มุมบนขวาของ WebStorm ให้คลิกรายการแบบเลื่อนลงทางด้านซ้ายของปุ่ม Run เลือก Android แล้วคลิก Run หรือ Debug หากคุณสร้างโปรเจ็กต์ด้วย Terminal คุณสามารถเพิ่ม React Native config ใหม่หรือเรียกใช้โดยใช้ Terminal:
cd AwesomeApeeScapeProject react-native run-android
หากทุกอย่างเป็นไปด้วยดีคุณจะพบกับหน้าจอต่อไปนี้:
รายการเด่นภายในโครงการ ได้แก่
มาสร้างโฟลเดอร์“ src” ภายในรูทของโปรเจ็กต์แล้วย้าย App.js ไปที่นั่น คุณจะต้องอัปเดตการนำเข้า index.js ให้ตรงกับตำแหน่ง App.js ใหม่
import App from './src/App';
ลบทุกอย่างใน App.js และวางรหัสนี้:
import React from 'react'; import {Text} from 'react-native'; export default class App extends React.Component { render() { return ( Hello TopTal ); } }
โค้ดที่เราวางนั้นค่อนข้างตรงไปตรงมา เราสร้างคลาส App
(ลูกของ React.Component
) ซึ่งแทนที่ render()
วิธีการและผลตอบแทน Text
ส่วนประกอบ. React.Component
เป็นคลาสพื้นฐานสำหรับการสร้าง UI โดยใช้ JSX export default
ตัวปรับเปลี่ยนทำให้คลาส public
.
ตอนนี้เราพร้อมที่จะเริ่มออกแบบเค้าโครงของเราแล้ว
Flexbox
คล้ายกับ LinearLayout
แต่ Flexbox
ไปไกลกว่าความสามารถของ LinearLayout
ตัวอย่าง JSX นี้:
flex: 1
แสดงเค้าโครงนี้:
ขณะนี้ XML:
android:layout_width='match_parent' android:layout_height='match_parent'
แสดงสิ่งนี้:
รหัส JSX ดูคุ้นเคยใช่มั้ย! มาสร้าง“ พจนานุกรม” (หรือกลโกง) สำหรับการออกแบบโดยใช้ JSX และ Android XML ที่มีลักษณะคล้ายกัน
โปรดทราบว่าฟังก์ชันการทำงานไม่จำเป็นต้องเท่ากัน ฉันกำลังพยายามช่วย React Native มือใหม่ให้เข้าใจแนวคิดของระบบเค้าโครงใน React Native โปรดอ้างอิง คู่มืออย่างเป็นทางการ สำหรับข้อมูลโดยละเอียด
พิจารณาคุณสมบัติ JSX นี้:
flexDirection
เทียบเท่ากับสิ่งนี้:
alignItems
ตัวอย่าง JSX นี้:
justifyContent
และ XML นี้:
flexDirection: row',
ทั้งสองสร้างผลลัพธ์นี้:
ในทำนองเดียวกัน JSX นี้:
works on Y axis and
และ XML นี้:
works on X axis. Everything is mirrored for
สร้างสิ่งนี้:
เพื่อให้ได้ตำแหน่งที่ถูกต้องภายในคอนเทนเนอร์เรามักจะใช้การรวมกันของ justifyContent
, alignItems
และ justifyContent
คุณสมบัติ.
JSX นี้:
space-around
และ XML นี้:
space-between
จะสร้างเค้าโครงนี้:
JSX นี้:
space-evenly
และ XML นี้
state
จะสร้างเค้าโครงนี้:
JSX นี้:
state
และ XML นี้:
render()
จะสร้างเค้าโครงนี้:
JSX นี้:
import React from 'react'; import {Button, Text, View} from 'react-native'; export default class App extends React.Component { /* Initialize state object with variable 'number' set to 0 and variable name with value of empty string */ state = {number: 0}; render() { return ( this.decrement()}/> {/* Text will be automatically updated whenever state.number has changed value */} Value = {this.state.number} this.increment()}/> ); } //Declaration of decrement function decrement() { //To update the state we need invoke this.setState //with new value for variable 'number' this.setState({number: this.state.number - 1}); } increment() { this.setState({number: this.state.number + 1}); } }
และ XML นี้:
textView.setText('Value ' + number)
จะสร้างเค้าโครงนี้:
บทเรียนที่ต้องเรียนรู้: ถ้าเรามี yarn
alignItems yarn add axios
justifyContent npm
flexDirection: column ’- npm install axios
มีผลต่อแกน Y และ import React from 'react'; import { TextInput, View, Text, Image, ActivityIndicator, Platform, StyleSheet } from 'react-native'; import axios from 'axios'; TextInput = EditText, ActivityIndicator = ProgressBar Platform - Platform detecting module StyleSheet - Module for creating stylesheets and moving them away from JSX
ส่งผลกระทบต่อแกน Y
justifyContent: 'ดิ้นเริ่มต้น' | แรงโน้มถ่วง = 'เริ่ม | ซ้าย' |
alignItems: 'ดิ้นเริ่มต้น' | แรงโน้มถ่วง = 'เริ่ม | ซ้าย' |
justifyContent: 'ปลายดิ้น' | แรงโน้มถ่วง = 'ท้าย | ขวา' |
alignItems: 'ปลายดิ้น' | แรงโน้มถ่วง = 'ท้าย | ขวา' |
ลองด้วยตัวคุณเอง ตั้ง export default class App extends React.Component { }
ค่าเป็น state = {text: '', loading: false, error: null, imgUrl: null};
, TextInput
และ Image
.
สำหรับการอัปเดตสถานะแอปพลิเคชันคุณจะใช้ React's render() { return ( //Predefined style. See below {/* returnKeyType ~ imeOptions onSubmitEditing ~ et.OnEditorActionListener */} this.setState({text})} onSubmitEditing={() => this.searchPicture()}/> {/* Render error Image component if this.state.imgUrl is not equal to null */} { this.state.imgUrl && } ); }
ตัวแปร. เมื่อไรก็ตาม onChangeText={(text) => this.setState({text})} onSubmitEditing={() => this.searchPicture()} { this.state.imgUrl && }
มีการปรับปรุง EditText
ถูกเรียกใช้
คัดลอกโค้ดด้านล่างไปยังแอปของคุณ:
TextWatcher
หากคุณคลิกปุ่มการปฏิเสธและการลงทะเบียนคุณจะเห็นว่าข้อความนั้นได้รับการอัปเดตโดยอัตโนมัติสำหรับคุณ ไม่จำเป็นต้องใช้ et.OnEditorActionListener
อย่างชัดเจน
ฟังก์ชันของรัฐมีประโยชน์ด้วยเหตุผลหลายประการ:
ตอนนี้เรามีข้อมูลพื้นฐานแล้วเรามาสร้างสิ่งที่ซับซ้อนขึ้นเล็กน้อยนั่นคือแอปค้นหา / r / pics Reddit ให้ปลายทาง JSON API ที่ตรงไปตรงมาดังนั้นเราจึงไม่ต้องทำภารกิจด้านข้างเพื่อรับการตรวจสอบสิทธิ์เพื่อให้ทำงานได้อย่างถูกต้อง
React Native มี Fetch API ในตัว เนื่องจากพวกเราส่วนใหญ่อาจจะเคยชิน ชุดติดตั้งเพิ่มเติม และใช้งานง่ายเราจะใช้ แกน . คุณสามารถติดตั้ง แกน ผ่านคำสั่งเทอร์มินัล
ใช้ searchPicture()
(วิธีที่ฉันชอบ):
imgUrl
หรือใช้ this.state.imgUrl
:
0
การนำเข้า:
false
สร้างชั้นเรียน:
null
เพื่อเริ่มต้นสถานะ เราต้องการ:
undefined
เพิ่มรหัส JSX เรามีเค้าโครงแนวตั้งด้วย searchPicture() { //Default state this.setState({loading: true, error: null, imgUrl: null}); axios.get('https://www.reddit.com/r/pics/search.json', { params: { //the get param map restrict_sr: 'on', //search only /r/pics limit: 1, //limit to one search item sort: 'new', //sort by creation date q: this.state.text //our search query } }).then(response => { //promise is resolved and 'then' block is triggered //set state with new values this.setState({ imgUrl: response.data.data.children[0] .data.preview.images[0].source.url, error: null, loading: false }) }).catch(error => {//Some error occurred //set error this.setState({error: error.message, loading: false, imgUrl: null}) }) }
และ ActivityIndicator
ส่วนประกอบ
Image
สิ่งใหม่:
{ //Separate method this.renderProgress() } {/* Render error Text component if this.state.error is not equal to null */} { this.state.error && {this.state.error} }
วิธีแรกทำงานคล้ายกับ render()
ด้วย renderProgress() { //If this.state.loading is true //return View containing a progressbar //View takes style array if (this.state.loading === true) { return ( ); } }
ส่วนประกอบ. บอกตามตรงว่า React Native ดีกว่ามาก
วิธีที่สองจะถูกเรียกใช้เมื่อกดปุ่มย้อนกลับบนแป้นพิมพ์ (App
) หลังจากทริกเกอร์ const styles = StyleSheet.create({ containerStyle: { flexDirection: 'column', flex: 1, //Since React Native is cross platform //let's handle both platforms. //Add top margin to fix status bar overlap marginTop: Platform.OS === 'ios' ? 20 : 0, }, textInputStyle: { marginLeft: 16, marginRight: 16, height: Platform.OS === 'ios' ? 30 : undefined } });
ภาพจะแสดงเมื่อ TextInput
ไม่เป็นค่าว่างหรือไม่ได้กำหนดเนื่องจากโอเปอเรเตอร์ '&&' ไม่ได้ตรวจสอบอาร์กิวเมนต์ที่สองหากอันแรกเป็นเท็จอยู่แล้ว
คุณอาจสงสัยว่าทำไม autoFocus={true} prop
เป็นเท็จ เมื่อใช้ตัวดำเนินการเชิงตรรกะใน JavaScript สิ่งใดก็ตามยกเว้น ‘’ (สตริงว่าง), TextInput
, ref={ref => this.searchInput = ref}
, componentDidMount()
หรือ componentDidMount(){ this.searchInput.focus(); }
เป็นความจริง ไม่จำเป็นต้องตรวจสอบเฉพาะ
constructor()
ไปเลย. แอปพลิเคชันควรทำงานตามที่คาดไว้ในขณะนี้ ป้อนสตริงการค้นหาแล้วกด return
เนื่องจากแอปพลิเคชันของเราพร้อมที่จะแสดงผล static _getDerivedStateFromProps_(props, state)
และข้อผิดพลาดเราต้องเพิ่มโค้ดเพิ่มเติมหลังจาก render()
ส่วนประกอบ:
componentDidMount()
คุณสามารถย้ายองค์ประกอบการแสดงผลภายนอก shouldComponentUpdate(nextProps, nextState)
วิธีการด้วย:
render()
ทั้งหมดคือสไตล์ วางสิ่งเหล่านี้ไว้นอก getSnapshotBeforeUpdate(prevProps, prevState)
ชั้นเรียน
componentDidUpdate(prevProps, prevState, snapshot)
ตอนนี้เราสามารถปรับแต่งเพิ่มเติมได้เช่นการเปิดซอฟต์คีย์บอร์ดโดยอัตโนมัติเมื่อเปิดแอพพลิเคชั่น
โปรดทราบว่ามีวิธีที่ง่ายกว่าในการสร้าง render()
โฟกัสอัตโนมัติ (componentWillUnmount()
) แต่เพื่อประโยชน์ของตัวอย่างนี้เราจะไม่ใช้มัน
เพิ่มการอ้างอิงไปที่ React.Component
ด้วยเสา:
./src
และแทนที่ CardView.js
วิธีวงจรชีวิตดังนี้:
import React from 'react'; import {View} from 'react-native'; export default CardView = (props) => { return ( //Style will be merged from default containerStyle //and props.style. props.style attributes will override //values if parameters are same. {/* props.children contain subviews add this line if the component is container */} {props.children} ); }; const styles = { containerStyle: { borderRadius: 4, margin: 5, padding: 5, elevation: 5, shadowColor: 'black', shadowRadius: 5, shadowOpacity: 0.5, shadowOffset: {width: 0, height: 3}, backgroundColor: 'white' } };
โหลดแอพใหม่แล้วคีย์บอร์ดจะเปิดให้เราโดยอัตโนมัติ
เราได้สร้างส่วนประกอบแล้ว แต่เราจะมาดูอายุของส่วนประกอบกัน
ขั้นตอนวงจรชีวิตของ React มีดังนี้
LoginForm
- ตัวสร้างจะถูกเรียกเสมอเมื่อแอปพลิเคชันเริ่มทำงานCardView
- เรียกก่อนแสดงผลและหลังการอัปเดต ส่งคืนวัตถุสำหรับการอัปเดตสถานะ คืนค่าว่างเพื่ออัปเดตอะไรเลยimport React from 'react'; import {TextInput, Platform, Button, StyleSheet} from 'react-native'; import CardView from '../common/components/CardView'; export default class LoginForm extends React._Component _{ render() { return ( //Override default style console.log('onLoginPress')} buttonStyle={styles.buttonStyle}/> ); } } const styles = StyleSheet.create({ buttonStyle: { elevation: 5, height: 40 }, textInputStyle: { padding: 10, //Additional params to make //iOS inputs prettier ...Platform.select({ ios: { borderRadius: 2, marginTop: 5, backgroundColor: '#eeeeee' } }) } });
- จำเป็นต้องมีการ Render สำหรับทุกคลาส React Component ใช้ในการแสดงผล ViewLoginForm
- ถูกเรียกใช้หลังจากคอมโพเนนต์ถูกแสดงผลและติดตั้งเข้ากับทรีมุมมองApp
- เรียกว่าหลังจากเปลี่ยนสถานะหรืออุปกรณ์ประกอบฉาก การส่งคืนค่าเริ่มต้นเป็นจริงหลังจากการอัพเดตสถานะทุกครั้ง เรียก View
ถ้าส่งคืนจริงreact-navigation
- เรียกก่อนที่จะมีการคอมมิตเอาต์พุตที่แสดงผลyarn
- เรียกว่าหลังจากแสดงอัปเดตใหม่ จะไม่ถูกเรียกหลังจากครั้งแรก npm
.axios
- เรียกก่อนที่ส่วนประกอบจะถูกยกเลิกการต่อเชื่อมและทำลาย
เรามักจะต้องสร้างส่วนประกอบที่ใช้ซ้ำได้เมื่อทำงานในโครงการ มีสองวิธีในการสร้างส่วนประกอบ:
yarn
. ควรใช้วิธีนี้หากเราต้องการวิธีวงจรชีวิตเนื่องจากเราได้สร้างคลาสคอมโพเนนต์แล้วเรามาสร้างฟังก์ชันสำหรับอินสแตนซ์นี้กัน
สมมติว่าเราต้องการอะนาล็อกเป็น สร้างโฟลเดอร์ 'ทั่วไป' ภายใต้ npm
ไดเรกทอรี
สร้าง PictureList.js:
.
import React from 'react'; import { ActivityIndicator, FlatList, Image, Text, TouchableHighlight, View } from 'react-native'; import axios from 'axios'; import CardView from '../common/CardView'; export default class PictureList extends React.Component { state = {loading: true, error: null, posts: null}; componentDidMount() { axios.get('https://www.reddit.com/r/pics.json') .then(response => { this.setState({ posts: response.data.data.children, loading: false }) }).catch(error => { this.setState({ error: error.message, loading: false }) }) } render() { return ( // FlatList ~ ListView // data - DataSource for the List // renderItem - function returns View item // keyExtractor - Unique id for items {this.state.posts && (item.data.id + '')}/>} {this.state.loading && } ); } navigateToPicture(title, url) { this.props.navigation.navigate('PicturePreview', { 'title': title, 'url': url }) } renderItem(item) { //Destructuring values from item //Read more 'ES6 destructuring' const {data} = item.item; const {title} = data; const {url} = data.preview.images[0].source; return ( //Clickable view this.navigateToPicture(title, url)}> {/Reusing our CardView/} {title} ) } }
PicturePreview.js
โดยใช้ import React from 'react'; import {Image} from 'react-native'; export default class PicturePreview extends React.Component { //Destructure navigation //Set title to header static _navigationOptions = ({navigation}) => ({ title: navigation.state.params.title }); render() { const {url} = this.props.navigation.state.params; return () } }
ใหม่ของเรา เค้าโครง:
navigationOptions
นำเข้า StackNavigation
ชั้นเรียนใน import React from 'react'; import {createStackNavigator} from 'react-navigation'; import PictureList from './components/PictureList'; import PicturePreview from './components/PicturePreview'; export default class App extends React.Component { render() { return ( ); } } //Customize the header_ const NavigationOptions = { headerTintColor: '#fff', headerStyle: { backgroundColor: '#f4511e', } }; //Create the router. const Router = createStackNavigator({ //Name the screen 'PictureList': { //Link the Component screen: PictureList, //Additional navigation options navigationOptions: { title: '/r/pics Browser', ...NavigationOptions } }, 'PicturePreview': { screen: PicturePreview, navigationOptions: NavigationOptions } }, { //Root initialRouterName: 'PictureList' } );
ชั้นเรียนและปิดท้ายด้วย
|_+_|
|_+_|
หากคุณปรับแต่งพารามิเตอร์ในสไตล์คุณจะได้สิ่งที่ดูดีกว่ามาก
การนำทางไปยังฉากต่างๆเป็นส่วนสำคัญสำหรับแอปพลิเคชันส่วนใหญ่ เรากำลังจะสร้างแอปเบราว์เซอร์ Reddit / r / pics
การสร้างการนำทางใน React Native นั้นค่อนข้างง่าย
ข้อกำหนดเบื้องต้น
|_+_|ด้วย หรือ
|_+_|ด้วย
|_+_|หรือ
เริ่มต้นด้วยการสร้างส่วนประกอบ 2 อย่างที่แตกต่างกัน
หมายเหตุ: โค้ดด้านล่างส่วนใหญ่น่าจะคุ้นเคยกับคุณอยู่แล้ว ฉันจะแปะทั้งชั้นเรียน
: จะถูกเรียกโดยอัตโนมัติโดย React-Navigationตอนนี้เราจะย้ายไปที่ App.js
หมายเหตุ: มีการนำทางหลายประเภทใน React-Navigation วันนี้เราจะเน้นไปที่ โปรดดูที่เว็บไซต์อย่างเป็นทางการสำหรับข้อมูลโดยละเอียด
อย่างที่คุณเห็นสิ่งที่เราต้องทำคือสร้างเราเตอร์นำทางและสร้างไฟล์ แอป แสดงผล หากทุกอย่างเป็นไปด้วยดีเราจะมีแอปเบราว์เซอร์ Reddit / r / pics ที่ใช้งานได้
Android:
iOS:
ตั้งแต่ฉันเริ่มเขียนโปรแกรมฉันมีประสบการณ์ในการพัฒนาอุปกรณ์เคลื่อนที่อย่างแท้จริง แต่ตอนนี้ฉันสามารถเขียนโค้ดสำหรับอะไรก็ได้ด้วย React: มือถือเดสก์ท็อปและเว็บ
หากคุณตัดสินใจที่จะเริ่มพัฒนาแอปพลิเคชันที่ยอดเยี่ยมต่อไปของคุณโดยใช้ไฟล์ ตอบสนองดั้งเดิม คุณจะพบว่ามันมีนิสัยแปลก ๆ และมีจุดบกพร่องอยู่ตรงนี้ แต่ React Native นั้นใช้งานได้ดีและเหมาะสำหรับโครงการส่วนใหญ่
ที่เกี่ยวข้อง: สร้างเครื่องสแกน QR: การสอนการตอบสนองกล้องเนทีฟสภาพแวดล้อมการพัฒนาแบบบูรณาการหรือตัวแก้ไขโค้ด
แอปพลิเคชั่นยอดนิยมจำนวนมากใช้ประโยชน์จาก React Native รวมถึง Facebook, Tesla, Skype, Instagram, Uber และอื่น ๆ
JavaScript
Flexbox เป็นวิธีการสร้างเลย์เอาต์ใน React Native
ในระยะสั้นไม่ การเขียนโปรแกรมโค้ดสำหรับ React Native ซึ่งเป็น JavaScript ไม่ได้คอมไพล์เป็น Java หรือ Swift / Objective C อย่างแท้จริงดังนั้นจึงยังคงต้องใช้เอ็นจิ้น JavaScript เพื่อทำงาน อย่างไรก็ตาม UI ใช้ส่วนประกอบเนทีฟจึงเป็นแบบเนทีฟสำหรับอินเทอร์เฟซผู้ใช้
ใช่. React Native เป็นเฟรมเวิร์กสำหรับการสร้างแอพที่มี Native UI