React 快速入门(1)

create-react-app myApp

cd myApp

npm start

这样你就简单的完成了一个 react app 建立,其目录结构如下( 图中不包括 node_modules 目录,下同 ):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Hello World


我们删除一些不必要的东西,然后修改目录结构如下(不能删 node_modules 目录,如果删了就在项目目录下运行 npm i 就好了):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 components 是个目录。

修改 index.js 如下:

import React from ‘react’;

import ReactDOM from ‘react-dom’;

ReactDOM.render(

hello world!

,

document.getElementById(‘root’)

);

然后命令行运行:

npm start

你就可以看到熟悉的 ‘hello world’ 了

JSX

JSX 是 react 中允许 js 和 html 混写的语法格式,需要依赖 babel 编译。这里我就只研究它的语法:

const element =

Hello, world!

;

可以通过花括号在其中插入表达式:

function formatName(user){

return user.firstName + ’ ’ + user.lastName;

}

const user = {

firstName: ‘Harper’,

lastName: ‘Perez’

};

const element = (

Hello, {formatName(user)}!

);

ReactDOM.render(

element,

document.getElementById(‘root’)

);

可以将 HTML 语句写为多行以增加可读性,用小括号括起来可以防止自动插入分号导致的错误。

JSX 也是个表达式,所以可以用在 for 和 if 中:

function getGreeting(user){

if (user){

return

Hello, {formatName(user)}!

;

}

return

Hello, Stranger.

;

}

我们可以正常使用引号给 HTML 标签添加属性,也可以使用 js 表达式

const element =

;

const element = ; //注意空标签以 /> 结尾,像 XML 一样

注意 html 属性名请使用小驼峰(camelCase)写法

React 会在渲染之前 escape 所有在 JSX 嵌入的值,可以有效的防止 XSS 攻击。

babel 会编译 JSX 成 React.createElement() 的参数调用:

const element = (

Hello, world!

);

// 编译为以下形式

const element = React.createElement(

‘h1’,

{className: ‘greeting’},

‘Hello, world!’

);

而 React.createElement() 会生成这样一个对象(React 元素):

const element = {

type: ‘h1’,

props: {

className: ‘greeting’,

children: ‘Hello, world’

}

};

元素渲染


./public/index.html 中有一个 id 为 root 的 div。我们将这个 div 作为 react 渲染的容器。

回看 hello world 程序,通过 ReactDOM.render() 方法很轻松的把内容渲染到了目标容器上:

ReactDOM.render(

hello world!

,

document.getElementById(‘root’)

);

当然也可以这样写:

let content =

hello world!

;

ReactDOM.render(

content,

document.getElementById(‘root’)

);

下面我们写一个复杂的,这是个实时更新的时钟,通过 setInerval 每隔 1s 调用 ReactDOM.render:

function Tick(){

const element = (

Hello, world!

It is {new Date().toLocaleTimeString()}.

);

ReactDOM.render(

element,

document.getElementById(‘root’)

);

}

setInterval(Tick, 1000);

重写上面时钟组件的代码如下,使其组件化程度更高:

function Clock(props){

return (

Hello, world!

It is {props.date.toLocaleTimeString()}.

);

}

function Tick(){

ReactDOM.render(

//这个地方不得不传入一个参数, 但理论上获取一个时钟直接获取就可以了,这个问题我们后面再解决

<Clock date={new Date()} />,

document.getElementById(‘root’)

);

}

setInterval(Tick, 1000);

组件

React 给我们提供了更好的管理我的代码——组件。这里我们还是首先我们先了解一下自定义标签:

const element = ;

对这个标签的理解也不难,它实际上调用了 Welcome 函数,并且将所有的属性(这里只有name)打包为一个对象传给 Welcome 函数。所以下面这个代码输出 ”Hello Sara”

function Welcome(props){

return

Hello, {props.name}

;

}

const element = ;

ReactDOM.render(

element,

document.getElementById(‘root’)

);

组件帮助我事先一些重复的工作,比如这样:

function Welcome(props){

return

Hello, {props.name}

;

}

function App(){

return (

);

}

ReactDOM.render(

,

document.getElementById(‘root’)

);

我们可以通过传递参数得到同一个组件构建的不同模块。

这里我们需要补充一个重要的概念:纯函数!!!

如果一个函数执行过程中不改变其参数,也不改变其外部作用于参数,当相同的输入总能得到相同的值时,我们称之这样的函数为纯函数。React 要求所有组件函数都必须是纯函数。

其实之前的一段代码中 Tick, Welcome 函数就可以看做是一个组件,同时 React 建议组件名的首字母大写。但是更多情况下我们会用到 es6 的语法构建组件。以之前时钟代码为例,转换过程分为五个步:

  1. 新建一个类,类名同组件函数名Clock,并继承自 React.Component;

  2. 给该类添加一个方法 render(/无参数/);

  3. 将 Clock 的函数体作为该函数的函数体;

  4. 将 render 方法中的 props 换为 this.props;

  5. 删除原有的 Clock 函数

结果如下:

class Clock extends React.Component {

render(){

return (

Hello, world!

It is {this.props.date.toLocaleTimeString()}.

);

}

}

但这样计时的功能就不能用了,我们继续往下看……

State 和 Lifecycle


解决上面这个问题,就需要用到 State 和 Lifecycle 的知识了

我们给 Clock 类添加一个构造函数,并且删除 Clock 标签中的参数:

class Clock extends React.Component {

constructor(props){

super(props);

this.state = {date: new Date()}; //state 用来记录状态

}

render(){

return (

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

);

}

}

ReactDOM.render(

, //删除参数

document.getElementById(‘root’)

);

为了控制计时的生命周期,我们需要引入 2 个方法 componentDidMount() 和 componentWillUnmount(),前者在渲染(render方法)完成时立即执行,后者在该 render 的内容即将被移除前执行。

很明显,前者适合注册计时器,后者可以用来清除计时器(防止内存泄露)

componentDidMount(){

this.timerID = setInterval(

() => this.tick(),

1000

);

}

componentWillUnmount(){

clearInterval(this.timerID);

}

下一步我们重写 tick 函数,此时的 tick 函数只需要修改 this.state 就行了。注意 React 要求不能直接修改该属性,而是使用 setState() 方法,所以 tick 函数如下:

tick(){

this.setState({

date: new Date()

});

}

这里需要注意的是,当 state 中有很多属性的时候,比如:

this.state = {name:“Lily”, age: 12};

执行 setState 方法修改其中的内容时并不会影响未修改的属性:

this.setState({name: “Bob”}); //此后 this.state 为 {name:“Bob”, age: 12};

此外 setState 可能是异步的,所以不要在更新状态时依赖前值:

// 这是个反例

this.setState({

counter: this.state.counter + this.props.increment,

});

为例解决这个问题,你可以传入函数参数:

// Correct

this.setState((prevState, props) => ({ //这里 prevState 更新前的 state 对象,props 为新值构成的对象

counter: prevState.counter + props.increment

}));

此时,完整的代码为:

class Clock extends React.Component {

constructor(props){

super(props);

this.state = {date: new Date()};

}

componentDidMount(){

this.timerID = setInterval(

() => this.tick(),

1000

);

}

componentWillUnmount(){

clearInterval(this.timerID);

}

tick(){

this.setState({

date: new Date()

});

}

render(){

return (

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

);

}

}

ReactDOM.render(

,

document.getElementById(‘root’)

);

事件

React 事件注册和原生 DOM 事件类似的,这里需要理解一些不同点即可:

  • 事件名使用小驼峰写法,而不是全小写,例如:onclick 写作 onClick

  • 注册事件使用花括号表达式替代原有函数写法

Click Here

  • 无法通过事件函数 return false 的方式阻止默认事件,必须显式的调用 preventDefault(),并且在使用时不用纠结浏览器兼容问题,React 已经帮你处理好了

  • React 建议通常不需要通过 addEventListener 添加事件,只需要像上方代码那样在 render 时绑定事件即可

  • 在 es6 语法的组件中注册事件只需要将事件函数定义为该类的一个方法,然后在 render 时绑定即可:

render(){

return (

Click Here…

);

}

  • 在 class 中,除了箭头函数定义的方法中 this 符合预期,其余方法中的 this 都是 undefined,应该手动绑定。因此以下三个按钮中 click2 会报错。

class Button extends React.Component {

constructor(){

super();

this.name = “Bob”;

this.click3 = this.click2.bind(this);

this.click1 = () => {

console.log(hello ${this.name});

}

}

click2(){

console.log(hello ${this.name});

}

render(){

return (

Click1

Click2

Click3

<button onClick={(e) => this.click2(e)}>Click3

);

}

}

  • 以上几种方法,React 推荐使用 click3 的实现方法,重写如下:

class Button extends React.Component {

constructor(){

super();

this.name = “Bob”;

this.click = this.click.bind(this);

}

click(){

console.log(hello ${this.name});

}

render(){

return (

Click me

);

}

}

  • 传递参数给事件的时候,第一个参数为 id, 第二个参数为 event。实际调用可以去以下两种方式:

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row

<button onClick={this.deleteRow.bind(this, id, e)}>Delete Row

  • 以上两种方法等效,后一个方法的参数 e 可以省略。

条件渲染


根据不同的条件(通常指state)渲染不同的内容, 比如下面段代码可以根据 isLoggenIn 渲染不同的问候语:

function UserGreeting(props) {

return

Welcome back!

;

}

function GuestGreeting(props) {

return

Please sign up.

;

}

function Greeting(props) {

const isLoggedIn = props.isLoggedIn;

if (isLoggedIn) { // 根据 isLoggenIn 渲染不同的问候语

return ;

}

return ;

}

ReactDOM.render(

// 你可以尝试设置 isLoggedIn={true}:

,

document.getElementById(‘root’)

);

下面用 class 实现一个复杂一点的,带有登录/注销按钮的:

function LoginButton(props) {

return (

登录

);

}

function LogoutButton(props) {

return (

注销

);

}

class LoginControl extends React.Component {

constructor(props) {

super(props);

this.state = {

isLoggedIn: false

};

// 修正 this 绑定

this.handleLoginClick = this.handleLoginClick.bind(this);

this.handleLogoutClick = this.handleLogoutClick.bind(this);

}

handleLoginClick() {

this.setState({isLoggedIn: true});

}

handleLogoutClick() {

this.setState({isLoggedIn: false});

}

render() {

const { isLoggedIn } = this.state;

let button = null;

if (isLoggedIn) {

button = ;

} else {

button = ;

}

return (

{/* Greeting 取自上一个示例 (注意这里的注释写法)*/}

{button}

);

}

}

ReactDOM.render(

,

document.getElementById(‘root’)

);

当然,对于这样一个简单的示例,使用 if 可能你会觉的太复杂了,我们也可以使用 && ?: 这些运算符来代替 if 语句,就像写 javascript 代码一样。我们极力的化简一下上面的代码:

class LoginControl extends React.Component {

constructor(props) {

super(props);

this.state = {

isLoggedIn: false

};

}

render() {

const { isLoggedIn } = this.state;

const button = isLoggedIn ?

<button onClick={() => { this.setState({isLoggedIn: false}); }}>注销
<button onClick={() => { this.setState({isLoggedIn: true}); }}>登录;

return (

{

isLoggedIn ? ‘Welcome back!’ : ‘Please sign up.’

}

{button}

);

}

}

ReactDOM.render(

,

document.getElementById(‘root’)

);

当然,如果你需要在某个条件下不进行渲染,那么直接输出 null 即可,比如下面这个组件,在 props.warnfalse 时不渲染任何内容:

function WarningBanner(props) {

if (!props.warn) {

return null;

}

return (

Warning!

);

}

需要注意的是,即便你输出了 null, react 也会再渲染一次。同理,componentWillUpdatecomponentDidUpdate 也会被调用。

列表

在 React 中我们可以使用 map() 方法渲染列表,比如如下这个例子,将一组数据映射(map)为一组 dom:

const data = [1, 2, 3, 4, 5];

const listItems = data.map((item) =>

  • {item}
  • );

    ReactDOM.render(

    • {listItems}
    ,

    document.getElementById(‘root’)

    );

    我们注意到这里我们给 li (即列表的每个元素)标签加了一个 key 属性,这个 key 用来帮助 React 判断哪个元素发生了改变、添加或移除。关于这个 key 我们需要明白以下几点:

    1. 最好保证 key 是一个字符串,并且在该列表中唯一,如果你的数据中实在没有唯一的 key 可以选择,那么就使用数组的索引(index)吧(不推荐这样)

    2. 值得注意的是,如果你不给每个元素指定一个 key, react 会默认使用索引(index)作为 key

    3. key 的值只是给 React 起到类似暗示的作用,不会真正的传递给 dom, 所以如果你需要使用 key 的值,应使用一个其它变量传递该值。

    当然,上面代码我们也可以写成 inline 的形式:

    const data = [1, 2, 3, 4, 5];

    ReactDOM.render(

      {

      data.map((item) =>

    • {item}
    • );

      }

      ,

      document.getElementById(‘root’)

      );

      表单

      表单的处理会和原生的 html 有一些区别,因为 React 可以很好的帮助你使用 js 控制你的表单,这里我们需要引入一个新的概念:受控组件。

      受控组件说白了就是其值受 react 控制的组件。其中,表单的元素通常都会具有其自己的 state,该值会随着用户的输入改变。比如下面这个例子,会在用户提交时输出用户的名字:

      class NameForm extends React.Component {

      constructor(props) {

      super(props);

      this.state = {value: ‘’};

      this.handleChange = this.handleChange.bind(this);

      this.handleSubmit = this.handleSubmit.bind(this);

      }

      handleChange(event) {

      this.setState({value: event.target.value});

      }

      handleSubmit(event) {

      alert('A name was submitted: ’ + this.state.value);

      event.preventDefault();

      }

      render() {

      return (

      Name:

      );

      }

      }

      不难发现,这里使用了,onchange 事件不断的将用户的输入绑定到 this.state.value 上,然后通过和用户输入同步的重绘实现数据的显示。这样可以很好的控制用户输入,比如同步的将用户输入转化为大写:

      handleChange(event) {

      this.setState({value: event.target.value.toUpperCase()});

      }

      理解了上面的内容我们可以知道,单纯给一个 input 赋值一个值用户是不能修改的,比如下面这行代码:

      ReactDOM.render(, mountNode);

      但如果你不小心他的值设为 null 或 undefined(等同于没有 value 属性),这个 input 就可以被更改了:

      ReactDOM.render(, mountNode);

      setTimeout(function() {

      ReactDOM.render(, mountNode);

      }, 1000);

      在 React 中 textarea 也是通过 value 属性实现其内容变化的,而非其子节点:

      class EssayForm extends React.Component {

      constructor(props) {

      super(props);

      this.state = {

      value: ‘Please write an essay about your favorite DOM element.’

      };

      this.handleChange = this.handleChange.bind(this);

      this.handleSubmit = this.handleSubmit.bind(this);

      }

      handleChange(event) {

      this.setState({value: event.target.value});

      }

      handleSubmit(event) {

      alert('An essay was submitted: ’ + this.state.value);

      event.preventDefault();

      }

      render() {

      return (

      Essay:

      ); } } 在 React 中,对于 select 也会显得很方便,你不需要在 option 中通过 selected 改变其值了,而是在 select 标签上通过 value 属性实现: class FlavorForm extends React.Component { constructor(props) { super(props); this.state = {value: 'coconut'}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert('Your favorite flavor is: ' + this.state.value); event.preventDefault(); } render() { return ( # 最后 **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。** **因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。** ![img](https://img-blog.csdnimg.cn/img_convert/95242f5678c990d5cdbf52babf701ead.jpeg) ![](https://img-blog.csdnimg.cn/img_convert/eaa34c37644eafc8b06c0aaf720e54dd.png) ![](https://img-blog.csdnimg.cn/img_convert/a51a4c582084adf1ad8f49f112e4a8f5.png) **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!** [**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618191877) **由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!** } } 在 React 中,对于 select 也会显得很方便,你不需要在 option 中通过 selected 改变其值了,而是在 select 标签上通过 value 属性实现: class FlavorForm extends React.Component { constructor(props) { super(props); this.state = {value: 'coconut'}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert('Your favorite flavor is: ' + this.state.value); event.preventDefault(); } render() { return ( # 最后 **自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。** **深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。** **因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。** [外链图片转存中...(img-YBPlXxtJ-1715584027645)] [外链图片转存中...(img-36WCNpc4-1715584027645)] [外链图片转存中...(img-p2s0RMWp-1715584027646)] **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!** [**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618191877) **由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**
    • 15
      点赞
    • 27
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值