文章目录
- 引子
 - React Native适用场景
 - React基础
 - JSX
 
- 组件的定义
 - 基础API
 - Flex弹性布局
 - 例子: Flex布局实现多行多列
 
- 常用UI组件
 - 几个核心钩子函数
 - useState用法
 - useEffect典型用法
 
- 和原生模块交互
 - 调用原生模块方法
 
- 调试
 - 其它工具
 - UI框架
 - 参考资源
 
引子
软件开发,移动优先;移动开发,RN优先。为什么?RN的性能胜任大部分应用场景,开发效率奇高(前提当然是熟悉web和javascript),热更新,快速见效,出活快,画一个界面三言两语,比原生简洁多了。Flutter? Xamarin? NativeScript? Ionic? Cordova? 我还是选RN。有人担心RN不流行了,会被替代,大可不必,哪种技术能长命百岁?一个产品有三五年的周期就算长寿了。RN短期内死不了。新的JS引擎 Hermes也极大地改进了性能。
关键词:JSX、Flex布局、UI组件
React Native适用场景
大部分应用都可以采用RN,新闻资讯类自不必说,电商类,教育类,视频播放类,也不在话下。CPU密集型?游戏类?这个我没有尝试过。但就像Java和C++/C的关系一样,80~90%都可以由Java搞掂,剩下的C来搞掂。你能吃下90%的业务部分,你还担心什么?

React基础
JSX
JSX 是 React 的核心组成部分,它使用 XML 标记的方式去直接声明界面。JSX貌似丑陋,和JS代码耦合,但其背后的哲学是每个HTML都是由有生命的片段组合而成,有了对片段的良好编程,就能由简到繁,积小成大,去构建更庞大的应用。
组件的定义
组件有两种写法:类组件和函数式组件。
 类的写法:
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
 
函数写法:
function Welcome(props) { 
  const data = [
    { id: 1, name: "John Doe" },
    { id: 2, name: "Victor Wayne" },
    { id: 3, name: "Jane Doe" },
  ];
  return (
  	<View>
	  	<Text>Hello, {props.name}</Text>
	    <View className="users">
	      {data.map((user) => (
	        <Text className="user">{user}</Text>
	      ))}
	    </View>
    </View>
  );
}
 
函数组件就是可以返回一个ReactElement的函数。
基础API


 ReactNode是一个联合类型:
type ReactNode =
  | ReactChild
  | ReactFragment
  | ReactPortal
  | boolean
  | null
  | undefined;
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
 
Flex弹性布局
定理:采用Flex加上嵌套能实现任意布局
-  
react 宽度基于pt为单位, 可以通过Dimensions 来获取宽高,PixelRatio 获取密度。
 -  
基于flex的布局
- view默认宽度为100%
 - 水平居中用alignItems, 垂直居中用justifyContent
 - 基于flex能够实现现有的网格系统需求,且网格能够各种嵌套无bug
 
 -  
图片布局
- 通过Image.resizeMode来适配图片布局,包括contain, cover, stretch
 - 默认不设置模式等于cover模式
 - contain模式自适应宽高,给出高度值即可
 - cover铺满容器,但是会做截取
 - stretch铺满容器,拉伸
 
 -  
定位
- 定位相对于父元素,父元素不用设置position也行
 - padding 设置在Text元素上的时候会存在bug。所有padding变成了marginBottom
 
 -  
文本元素
- 文字必须放在Text元素里边
 - Text元素可以相互嵌套,且存在样式继承关系
 - numberOfLines 需要放在最外层的Text元素上,且虽然截取了文字但是还是会占用空间
 
 
例子: Flex布局实现多行多列
容器: flex-wrap: wrap; 允许折行
 元素有三种方式:
- flex: 1 0 33.3%;
 - flex-basis: 33.3%;
 - width: 33.3%;
 
常用UI组件
View是最核心、最常用的UI组件。
 VirtualizedList是FlatList和SectionList的底层实现。FlatList和SectionList都依赖一个数组,每个元素是个字典,SectionList的字典必须有data、title、key。
- 不要在ScrollView里使用FlatList
 
 <View style={{flex: 1}} >
    <ScollView style={{flexGrow: 1}} 
     nestedScrollEnabled={true}>
        <View>
            <SafeAreaView>
                <ScrollView horizontal 
                style={{width: '100%', height: 'your_height'}}>
                  {data.map((item, index) => (
                    <View key={index}>
                      // Your component
                    </View>
                  ))}
                </ScrollView> -- Horizontal Scroll --
            </SafeAreaView>
        </View>        
    </ScrollView>
</View>
 
几个核心钩子函数
Hooks 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hooks 是一种在函数式组件中使用有状态函数的方法。Hooks不支持在class中使用,比如在class中使用useState和useEffect都是不允许的。
- useEffect()函数:作用就是指定一个副效应函数,组件每渲染一次,该函数就自动执行一次。组件首次在网页 DOM 加载后,副效应函数也会执行。它的第二个参数,使用一个数组指定副效应函数的依赖项,只有依赖项发生变化,才会重新渲染。
 - useState()函数:用于为函数组件引入状态。
 - useContext():用于在组件之间共享状态。
 - useReducer():React 本身不提供状态管理功能,通常需要使用外部库。这方面最常用的库是 Redux。Redux 的核心概念是,组件发出 action 与状态管理器通信。状态管理器收到 action 以后,使用 Reducer 函数算出新的状态,Reducer 函数的形式是(state, action) => newState。
 
| Hook函数 | 说明 | 
|---|---|
| useState | [<取值>, <设值>] = useState(<初始值>) | 
| useEffect | 在组件加载和监听的对象值发生变化时调用 | 
| useContext | |
| useLayoutEffect | |
| useReducer | |
| useCallback | |
| useMemo | |
| useRef | 返回一个mutable ref对象,用.current获得其值 | 
| useTransition | |
| useDeferredValue | |
| useId | 
useState用法
- useState的更新是异步的,数据不会立即刷新的。其背后是队列实现的。
 - 仅顶层调用,不能在循环,条件,嵌套函数等中调用useState()。
 
useEffect典型用法
const [data, setData] = useState()
useEffect(() => {
  // declare the async data fetching function
  const fetchData = async () => {
    // get the data from the api
    const data = await fetch(`https://yourapi.com?param=${param}`);
    // convert the data to json
    const json = await response.json();
    // set state with the result
    setData(json);
  }
  // call the function
  fetchData()
    // make sure to catch any error
    .catch(console.error);;
}, [param])
 
再举一个例子:
import { useState, useEffect } from 'react';
const HackerNewsStories = () => {
  const [stories, setStories] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  useEffect(() => {
    const fetchStories = async () => {
      try {
        const data = await (await fetch('https://hn.algolia.com/api/v1/search_by_date?tags=front_page&hitsPerPage=20')).json();
        setStories(
          data.hits.sort((story, nextStory) => (story.points < nextStory.points ? 1 : -1))
        );
        setError(null);
      } catch (err) {
        setError(err.message);
        setStories(null);
      } finally {
        setLoading(false);
      }
    };
    fetchStories();
  }, []);
  return (
    <div className="wrapper">
      <h2>Latest HN Stories</h2>
      {loading && <div>HackerNews frontpage stories loading...</div>}
      {error && <div>{`Problem fetching the HackeNews Stories - ${error}`}</div>}
      <div className="stories-wrapper">
        {stories &&
          stories.map(({ objectID, url, title, author, points }) => (
            title && url &&
            <div className='stories-list' key={objectID}>
              <h3><a href={url} target="_blank" rel="noreferrer">{title}</a> - By <b>{author}</b> ({points} points)</h3>
            </div>                        
          ))}
      </div>
    </div>
  );
};
export default HackerNewsStories;
 
和原生模块交互
在使用 React 做开发时有两种写法:
 类组件
 函数组件 + Hook (用的这种)
 React 组件之间共享数据的方案:
 使用 React 自带的 Context + Reducer 功能 (用的这种)
 优点:无须引入其他的包
 缺点:只能向子组件及子孙组件中共享数据
 使用 Redux 实际组件之间的共享
 优点:数据全都放到 Redux 中管理,无论什么层级都直接使用
 缺点:需要单独安装,数据状态由它统一管理,很多代码写法不太一样
 RN 中的布局
 View 组件默认是相对定位的(可以直接使用 left 、top 相对于原来的位置定位)
 View 组件的绝对定位都是相对于父组件定位的(因为父组件都是相对定位,所以默认都是子绝父相)
 没有浮动,只能 flex
 父组件一定要设置高度或者 flex:1 ,否则高度为0页面空白
调用原生模块方法
要实现一个自己的ReactPackage和ReactModule,在ReactModule中暴露js方法。
调试
调试方面强烈推荐使用 React Native Debugger,一个基于 React Native 官方调试方式、包含 React Inspector / Redux DevTools 独立应用:
- 基于官方的 Remote Debugger 且提供了更为丰富的功能
 - 包含 react-devtools-core 的 React Inspector
 - 包含 Redux DevTools, 且与 redux-devtools-extension 保持 API 一致
 
其它工具
- Watchman, Watchman 在更改时观察文件和记录,然后触发相应的操作,并由 React Native 在内部使用
 
UI框架
- react-native-elements
 - Ant Design Mobile RN
 
参考资源
- https://github.com/jondot/awesome-react-native
 - https://github.com/reactnativecn/react-native-guide
 - Expo官网
 - https://taro.zone/
 - https://nervjs.github.io/taro-docs/docs/GETTING-STARTED
 - 下载 Genymotion免费版
 - 多终端开发
 - https://oblador.github.io/react-native-vector-icons/
 



















