【React Native入门教程】React基础

前言

由于React Native 使用和React相同的API结构,所以了解学习React很有必要,本节带你快速入门React
在这里插入图片描述

import React from 'react';
import {Text} from 'react-native';

const FirstCompose = () => {
  return <Text>Hello</Text>;
};

export default FirstCompose;

这是最简单的一个React组件代码,第一步需要通过import导入你所需要的组件或库,这里就导入了React和Text,通过一个函数就可以声明一个组件,它的返回值可以被渲染。最后一步将你的组件通过export导出即可。

导入导出属于JavaScript语法,它有多种写法,详细可以查阅资料。https://zh.javascript.info/import-export

关注函数返回<Text>Hello</Text>:这是React用来描述UI元素的语法(JSX),属于JavaScript语法的一部分

JSX

需要注意的是,JSX语法是被包含在React库中,所以你需要在文件首部import React from 'react'导入。
由于JSX是属于JavaScript的一部分,所以你仍然可以使用JavaScript的其他语法,只需要用{}包裹起来即可。

import React from 'react';
import {Text} from 'react-native';

const getFullName = (
  firstName: string,
  secondName: string,
  thirdName: string,
) => {
  return firstName + ' ' + secondName + ' ' + thirdName;
};

const Cat = () => {
  return <Text>Hello, I am {getFullName('Rum', 'Tum', 'Tugger')}!</Text>;
};

export default Cat;

自定义复杂组件

我们也可以把多个组件组合在一起导出,在Android开发中,我们把View放到LinearLayout, FrameLayout, RelativeLayout等父布局中,并对其进行排列组合,在React中我们只需要使用<View>就可以把多个组件组合起来。<View></View>也可以简写成<></>

import React from 'react';
import {Text, View} from 'react-native';

const Cat = () => {
  return (
    <View>
      <Text>I am also a cat!</Text>
    </View>
  );
};

const Cafe = () => {
  return (
    <View>
      <Text>Welcome!</Text>
      <Cat />
      <Cat />
      <Cat />
    </View>
  );
};

export default Cafe;

在这个例子中,其他文件只需要使用<Cafe>就可以一次渲染全部组件。其中一个组件包含了另一个组件称为父组件

Prop

上一节只讲了如何定义一个复杂组件,但是并没有提供用户可选的参数。为自定义的组件添加参数很简单,就是为你声明的函数增加参数即可:

import React from 'react';
import {Text, View} from 'react-native';

type CatProps = {
  name: string;
};

const Cat = (props: CatProps) => {
  return (
    <View>
      <Text>Hello, I am {props.name}!</Text>
    </View>
  );
};

const Cafe = () => {
  return (
    <View>
      <Cat name="Maru" />
      <Cat name="Jellylorum" />
      <Cat name="Spot" />
    </View>
  );
};

export default Cafe;

使用TypeScript语法规定参数类型,参数的使用和正常的类调用一样,主要关注调用函数时的传参<Cat name="Maru" />。这是一种传参的方式,还有一种情况,大家可能会好奇,例如:<Text>Hello</Text>这种情况下这里的Hello传递以后是属于那个参数呢?

答案是:Hello 是传递给 children属性的值。children属性是一个特殊的属性,它允许您在组件中嵌套其他组件或文本。 我们顺便查看一下源码是不是这样。

export interface TextProps extends TextPropsIOS, TextPropsAndroid, AccessibilityProps {
    /**
     * Specifies whether fonts should scale to respect Text Size accessibility settings.
     * The default is `true`.
     */
    allowFontScaling?: boolean | undefined;

    children?: React.ReactNode;
    
    
    //...    
}

确实可以发现children属性,并且他是React.ReactNode类型。那我们推断一下是不是

<Text><Text>...</Text></Text>

这样也可以正常显示,甚至做更多自定义呢?

State

到目前为止,我们的页面都是静态的。我们可以使用useState定义一个可修改的变量,当其改变时,将会触发重新渲染

import React, {useState} from 'react';
import {Button, Text, View} from 'react-native';

type CatProps = {
  name: string;
};

const Cat = (props: CatProps) => {
  const [isHungry, setIsHungry] = useState(true);

  return (
    <View>
      <Text>
        I am {props.name}, and I am {isHungry ? 'hungry' : 'full'}!
      </Text>
      <Button
        onPress={() => {
          setIsHungry(false);
        }}
        disabled={!isHungry}
        title={isHungry ? 'Pour me some milk, please!' : 'Thank you!'}
      />
    </View>
  );
};

export default Cat;

在这个例子中,声明了isHungry这个变量,当点击按钮以后使用setIsHungry改变它的值。触发重新渲染,显示新的文本

useState

const [state, setState] = useState(initialState);

useState接受一个初始值,返回对应的变量和修改变量的方法,依次赋值给const [state, setState],这个语法叫做:解构赋值。当调用setState修改值时,会触发组件使用新值重新进行渲染。

  • initialState:不仅可以传递固定的值,还可以传递一个函数,这个函数不能有输入,必须有一个输出。如果你传递的仅是函数名, 那么这个函数只会在初始化第一次调用,如果你是传递的函数调用,那么每次渲染都会调用
function createInitialTodos() {
    return ...
}

function TodoList() {
    //如果这样传参,那么每次渲染都会重新调用createInitialTodos
    const [todos, setTodos] = useState(createInitialTodos());
  
    //如果只传参数名,那么仅会调用一次
    const [todos, setTodos] = useState(createInitialTodos);

}
  • setState:函数原型为:setState(S)或者setState((prevState: S) => S)
    这说明setState的调用也可以传递函数,函数的入参为上一次的值,需要返回更改后的值。
    对于对象,通过Object.is进行比较
//1. 
setState(false)

//2. 
setState((pre) => {
    //do something
    let ret = !pre
    return ret
})
  • state:代表当前的值,初始值是根据你传入的initialState决定

注意

  1. React会等待所有的State执行完成以后在批量进行渲染,如果你想立马执行渲染可以使用flushSync
  2. 当你调用set方法以后不会立马修改state的值,而是等待渲染的时候才会更改
const [name, setName] = useState('Taylor');

function handleClick() {
  setName('Robin');
  console.log(name); // Still "Taylor"!
}
  1. 如果你对set传递的参数是函数,那么这个函数会被加入队列中,在下一次渲染时依次执行
import { useState } from 'react';

export default function Counter() {
  const [age, setAge] = useState(42);

  function increment() {
    setAge(a => a + 1);
  }

  return (
    <>
      <h1>Your age: {age}</h1>
      <button onClick={() => {
        increment();
        increment();
        increment();
      }}>+3</button>
    </>
  );
}
//这里按钮触发会执行三次increment,也就是执行三次setAge,因为传递的是函数,并不会立马执行,
//而是丢入队列,等下次渲染时,依次执行,这样才可以达到依次点击,age + 3

//如果你不使用函数的方式递增,那么是会失败的
function increment() {
    setAge(a + 1);
    setAge(a + 1);
    setAge(a + 1);
}
//set函数执行后age的值不会立马改变,所以这里其实是调用了3此setAge(42 + 1)
//按钮点击后,依旧只增加1
  1. 对于state为对象或者数组的情况,由于state是只读的的属性,你应该替换它,而不是修改内部值
const [from, setFrom] = useState({firstName:"AAA"})

setForm({
  ...form,
  firstName: 'Taylor'
});
//这里也是一个解构赋值语句,实则是新建了一个对像

useEffect

useEffect(setup, dependencies?)
  • dependencies:是一个数组,里面包含了useEffect监听的值,当这些值产生变化后,会调用setup函数
    • 如果传递的数组内有值:那么则会在首次渲染时和数组内的值变化后,调用setup函数
    • 如果传递的数组是空数组:那么仅会在首次渲染时,调用setup函数
    • 如果完全没有传递这个参数:那么每次渲染,都会调用setup函数
  • setup:是一个函数,函数可以再返回一个"清理函数",首次渲染时,会调用setup函数,之后渲染如果你提供了清理函数,会先使用旧的dependencies执行清理函数,然后使用新值执行setup函数。当组件被移除时,会最后调用一次清理函数
import { useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    //清理函数
    return () => {
      connection.disconnect();
    };
  }, [serverUrl, roomId]);
  // ...
}

useRef

useRef(initialValue) 

返回一个仅包含current属性的对象,这个属性的初始值为你设置的initialValue。当下一次渲染时useRef会返回相同的对象,你可以改变current的值用来记录一些信息。它与useState的不同之处在于,当你修改current时不会触发渲染。

ref的另一个用处是可以控制DOM,如下例子

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

首先使用null声明一个ref,然后将其赋值给DOM的ref属性。在React创建这个DOM并渲染至屏幕上时,React会设置ref的current为这个DOM。然后就可以通过current操作它。当DOM从屏幕消失时,React会将current置为null。

memo

const MemoizedComponent = memo(SomeComponent, arePropsEqual?)

memo可以让组件当属性未改变时跳过渲染

  • SomeComponent:一个你需要处理的组件,memo会返回一个新的一模一样的组件
  • arePropsEqual:一个用户判断属性是否改变的函数,函数原型为:(preProp, newProp)=> bool如果未指定该参数,那么会使用object.is
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值