React Native – Architecture – Project structure & static resource management

How to avoid relative path when importing library?

Folder structure

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
screens
login
LoginScreen.js
LoginNavigator.js
onboarding
OnboardingNavigator
welcome
WelcomeScreen.js
term
TermScreen.js
notification
NotificationScreen.js
main
MainNavigator.js
news
NewsScreen.js
profile
ProfileScreen.js
search
SearchScreen.js
library
package.json
components
ImageButton.js
RoundImage.js
utils
moveToBottom.js
safeArea.js
networking
API.js
Auth.js
screens login LoginScreen.js LoginNavigator.js onboarding OnboardingNavigator welcome WelcomeScreen.js term TermScreen.js notification NotificationScreen.js main MainNavigator.js news NewsScreen.js profile ProfileScreen.js search SearchScreen.js library package.json components ImageButton.js RoundImage.js utils moveToBottom.js safeArea.js networking API.js Auth.js
  screens
    login
      LoginScreen.js
      LoginNavigator.js
    onboarding
      OnboardingNavigator    
      welcome 
        WelcomeScreen.js
      term
        TermScreen.js
      notification
        NotificationScreen.js
    main
      MainNavigator.js
      news
        NewsScreen.js
      profile
        ProfileScreen.js
      search
        SearchScreen.js  
  library
    package.json
    components
      ImageButton.js
      RoundImage.js
    utils
      moveToBottom.js
      safeArea.js
    networking
      API.js
      Auth.js

Turn library into a module

Turn library into a module so that Node can find it. Add “package.json” to any folder makes it into a Node module. Here is package.son file.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"name": "library",
"version": "0.0.1"
}
{ "name": "library", "version": "0.0.1" }
{
  "name": "library",
  "version": "0.0.1"
}

Usage

Instead of using relative path like this

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import moveToBottom from '../../../../library/utils/move'
import ImageButton from '../../../../library/components/ImageButton'
import moveToBottom from '../../../../library/utils/move' import ImageButton from '../../../../library/components/ImageButton'
import moveToBottom from '../../../../library/utils/move'
import ImageButton from '../../../../library/components/ImageButton'

we can use absolute path like this

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import moveToBottom from 'library/utils/moveToBottom'
import ImageButton from 'library/components/ImageButton'
import moveToBottom from 'library/utils/moveToBottom' import ImageButton from 'library/components/ImageButton'
import moveToBottom from 'library/utils/moveToBottom'
import ImageButton from 'library/components/ImageButton'

How to control static resource?

Folder structure

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
src
...
res
package.json
strings.js
colors.js
palette.js
fonts.js
images.js
images
logo@2x.png
logo@3x.png
button@2x.png
button@3x.png
R.js
src ... res package.json strings.js colors.js palette.js fonts.js images.js images logo@2x.png logo@3x.png button@2x.png button@3x.png R.js
src
  ...  
  res
    package.json
    strings.js
    colors.js
    palette.js
    fonts.js
    images.js
    images
      logo@2x.png
      logo@3x.png
      button@2x.png
      button@3x.png
    R.js

How to use one file to call all resource elements?

Learn from Android, all the resource can be called from R class. Resource ids are generated into R class after build

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import strings from './strings'
import images from './images'
import colors from './colors'
import palette from './palette'
const R = {
strings,
images,
colors,
palette
}
export default R
import strings from './strings' import images from './images' import colors from './colors' import palette from './palette' const R = { strings, images, colors, palette } export default R
import strings from './strings'
import images from './images'
import colors from './colors'
import palette from './palette'

const R = {
  strings,
  images,
  colors,
  palette
}

export default R

How to manage constant string resource?

Create a strings.js file

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const strings = {
onboarding: {
welcome: {
heading: 'Welcome',
text1: "What you don't know is what you haven't learn",
text2: 'Visit my GitHub at https://github.com/onmyway133',
button: 'Log in'
},
term: {
heading: 'Terms and conditions',
button: 'Read'
}
}
}
export default strings
const strings = { onboarding: { welcome: { heading: 'Welcome', text1: "What you don't know is what you haven't learn", text2: 'Visit my GitHub at https://github.com/onmyway133', button: 'Log in' }, term: { heading: 'Terms and conditions', button: 'Read' } } } export default strings
const strings = {
  onboarding: {
    welcome: {
      heading: 'Welcome',
      text1: "What you don't know is what you haven't learn",
      text2: 'Visit my GitHub at https://github.com/onmyway133',
      button: 'Log in'
    },
    term: {
      heading: 'Terms and conditions',
      button: 'Read'
    }
  }
}

export default strings

Create “package.json” file inside “res” folder

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"name": "res",
"version": "0.0.1"
}
{ "name": "res", "version": "0.0.1" }
{
  "name": "res",
  "version": "0.0.1"
}

Usage

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import R from 'res/R'
render() {
return (
<SafeAreaView style={styles.container}>
<Image
style={styles.logo}
source={R.images.logo} />
<Image
style={styles.image}
source={R.images.placeholder} />
<Text style={styles.title}>{R.strings.onboarding.welcome.title.toUpperCase()}</Text>
)
}
import R from 'res/R' render() { return ( <SafeAreaView style={styles.container}> <Image style={styles.logo} source={R.images.logo} /> <Image style={styles.image} source={R.images.placeholder} /> <Text style={styles.title}>{R.strings.onboarding.welcome.title.toUpperCase()}</Text> ) }
import R from 'res/R'

render() {
  return (
    <SafeAreaView style={styles.container}>
      <Image
        style={styles.logo}
        source={R.images.logo} />
      <Image
        style={styles.image}
        source={R.images.placeholder} />
      <Text style={styles.title}>{R.strings.onboarding.welcome.title.toUpperCase()}</Text>
  )
}

How to control app design

The design of the app should be consistent. Certain elements should have the same look and feel so they don’t confuse the user.

For example, the heading Text should use one color, font, and font size. The Image component should use the same placeholder image.

Create “res/palette.js”

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import colors from './colors'
const palette = {
heading: {
color: colors.title,
fontSize: 20,
textAlign: 'center'
},
text: {
color: colors.text,
fontSize: 17,
textAlign: 'center'
}
}
export default palette
import colors from './colors' const palette = { heading: { color: colors.title, fontSize: 20, textAlign: 'center' }, text: { color: colors.text, fontSize: 17, textAlign: 'center' } } export default palette
import colors from './colors'

const palette = {
  heading: {
    color: colors.title,
    fontSize: 20,
    textAlign: 'center'
  },
  text: {
    color: colors.text,
    fontSize: 17,
    textAlign: 'center'
  }
}

export default palette

Usage

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center'
},
heading: {...palette.heading, ...{
marginTop: 72
}}
})
const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center' }, heading: {...palette.heading, ...{ marginTop: 72 }} })
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center'
  },
  heading: {...palette.heading, ...{
    marginTop: 72
  }}
})

How to control internal images?

Folder structure

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
src
...
res
images.js
images
logo@2x.png
logo@3x.png
button@2x.png
button@3x.png
scripts
images.js
clear.js
src ... res images.js images logo@2x.png logo@3x.png button@2x.png button@3x.png scripts images.js clear.js
src
  ...
  res
    images.js
    images
      logo@2x.png
      logo@3x.png
      button@2x.png
      button@3x.png
scripts
  images.js
  clear.js

Create images.js

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const images = {
button: require('./images/button.png'),
logo: require('./images/logo.png'),
placeholder: require('./images/placeholder.png')
}
export default images
const images = { button: require('./images/button.png'), logo: require('./images/logo.png'), placeholder: require('./images/placeholder.png') } export default images
const images = {
  button: require('./images/button.png'),
  logo: require('./images/logo.png'),
  placeholder: require('./images/placeholder.png')
}

export default images

Usage

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import images from 'res/images'
import colors from 'res/colors'
export default class ImageButton extends React.Component {
render() {
return (
<TouchableOpacity style={styles.touchable} onPress={this.props.onPress}>
<View style={styles.view}>
<Text style={styles.text}>{this.props.title}</Text>
</View>
<Image
source={images.button}
style={styles.image} />
</TouchableOpacity>
)
}
}
import images from 'res/images' import colors from 'res/colors' export default class ImageButton extends React.Component { render() { return ( <TouchableOpacity style={styles.touchable} onPress={this.props.onPress}> <View style={styles.view}> <Text style={styles.text}>{this.props.title}</Text> </View> <Image source={images.button} style={styles.image} /> </TouchableOpacity> ) } }
import images from 'res/images'
import colors from 'res/colors'

export default class ImageButton extends React.Component {
  render() {
    return (
      <TouchableOpacity style={styles.touchable} onPress={this.props.onPress}>
        <View style={styles.view}>
          <Text style={styles.text}>{this.props.title}</Text>
        </View>
        <Image
          source={images.button}
          style={styles.image} />
      </TouchableOpacity>
    )
  }
}

How to automatically update “images.js” when images folder is changed

Add /scripts/images.js

Simply traverse through images, and update /src/res/images.js accordingly

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const fs = require('fs')
const imageFileNames = () => {
const array = fs
.readdirSync('src/res/images')
.filter((file) => {
return file.endsWith('.png')
})
.map((file) => {
return file.replace('@2x.png', '').replace('@3x.png', '')
})
return Array.from(new Set(array))
}
const generate = () => {
let properties = imageFileNames()
.map((name) => {
return `${name}: require('./images/${name}.png')`
})
.join(',\n ')
const string = `const images = {
${properties}
}
export default images
`
fs.writeFileSync('src/res/images.js', string, 'utf8')
}
generate()
const fs = require('fs') const imageFileNames = () => { const array = fs .readdirSync('src/res/images') .filter((file) => { return file.endsWith('.png') }) .map((file) => { return file.replace('@2x.png', '').replace('@3x.png', '') }) return Array.from(new Set(array)) } const generate = () => { let properties = imageFileNames() .map((name) => { return `${name}: require('./images/${name}.png')` }) .join(',\n ') const string = `const images = { ${properties} } export default images ` fs.writeFileSync('src/res/images.js', string, 'utf8') } generate()
const fs = require('fs')

const imageFileNames = () => {
  const array = fs
    .readdirSync('src/res/images')
    .filter((file) => {
      return file.endsWith('.png')
    })
    .map((file) => {
      return file.replace('@2x.png', '').replace('@3x.png', '')
    })
    
return Array.from(new Set(array))
}

const generate = () => {
  let properties = imageFileNames()
    .map((name) => {
      return `${name}: require('./images/${name}.png')`
    })
    .join(',\n  ')
    
const string = `const images = {
  ${properties}
}

export default images
`

fs.writeFileSync('src/res/images.js', string, 'utf8')
}

generate()

Update images folder by running this script

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
node scripts/images.js
node scripts/images.js
node scripts/images.js

or config main “package.json”

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest",
"lint": "eslint *.js **/*.js",
"images": "node scripts/images.js"
}
"scripts": { "start": "node node_modules/react-native/local-cli/cli.js start", "test": "jest", "lint": "eslint *.js **/*.js", "images": "node scripts/images.js" }
"scripts": {
  "start": "node node_modules/react-native/local-cli/cli.js start",
  "test": "jest",
  "lint": "eslint *.js **/*.js",
  "images": "node scripts/images.js"
}

and run

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
npm run images
npm run images
npm run images

Be the first to comment

Leave a Reply

Your email address will not be published.


*