React 从入门到入门

    科技2022-08-27  103

    React 从入门到入门

    这篇文章讲了 React 的基础知识,从 JSX 语法到面向组件编程:组件的属性 state,props,refs等属性 这是初学者写下的笔记,如有错误,欢迎指正!

    React:JavaScript库 (和 jQuery 一样是个库)和 Vue 一样都尽量减少 DOM 的操作Facebook 出品的前端框架

    How would you React if I said I love Vue?

    React HelloWorld

    <div class="test"></div> <script type="text/babel"> // 创建虚拟 DOM var vdom = <h1>Hello React</h1>; // 将虚拟 DOM 渲染到页面 ReactDOM.render(vdom, document.querySelector('.test')); </script>

    刚上来的时候就给我来了一个报错,弄得我很懵,其实是内嵌 script 中 type 属性 应该为 type="text/babel" 否则会报一个出现意外的小于号的错(也就是无法解析 script 里面写的其他标签)

    react.js:React 的核心库

    react-dom.js:提供操作 DOM 的 react 扩展库

    babel.min.js:解析 jsx => js代码 (将 ES6 语法转换成 ES5)

    虚拟 DOM

    React 创建虚拟 DOM 对象: var myTitle = 'noobMing'; var element = React.createElement('h1',{id:myTitle},myTitle); // 这种方法需要 babel 标签 const vDom = <h1 id={myTitle}>{myTitle}</h1> 创建好的元素: <h1 id="noobMing">noobMing</h1>

    大写转换成小写:.toLowerCase() 小写转换成大写:.toUpperCase()

    debugger 关键字:相当于在书写处添加了一个断点

    JSX

    全称 JavaScript XML

    和 XML 一样都可以自定义标签 (之后叫组件标签)

    babel.js 将 JSX 代码转换成纯 js 代码

    假如有可能出现嵌套的 HTML 结构那么最好用括号括起来

    如果我想用 li 渲染整个列表,那么我可以这么做:

    let names = ['jquery', 'react', 'vue', 'angular']; // 例如: const ul = (<ul> {names.map((name,index)=>{return <li key={index}>{name}</li>})} </ul>) // 渲染到页面 ReactDOM.render(ul, document.querySelector('.test'));

    这就是虚拟 DOM 吗,我开始的时候想遍历整个列表,然后把他们边包裹成 li 边放到创建好的 ul 里面去,结果他不是在原来的 li 后面接着添加,而是直接覆盖掉前一个,又费事有没达到效果,看了老师的操作我想说还可以这么弄

    和 Vue 小程序 一样,React 强制要求循环需要一个 key 属性来确保这个属性是唯一的

    面向组件编程

    组件标签首字母要大写分成两步:1.定义组件,2.渲染组件标签和 vue 的组件一样,最外层都要有一个父元素做包裹定义组件一共有三种方式: // 1. 工厂函数组件 (简单组件) function MyComponent() { return <h2></h2>; } // 渲染标签 ReactDOM.render(<MyComponent />,document.querySelector('div')); 在真实 DOM 中,浏览器会将组件的最外层标签给去掉,只留下组件内部的标签 // ES6 的类组件 (复杂组件) class MyComponent2 extends React.Component { render() { return <h2>ES6 的类组件 (复杂组件)</h2> } } 在这里输出的 this 指向组件对象

    组件的状态:state

    state 叫做状态机,值是对象,通过更新组件的 state 来更新组件的显示下面这段代码是你点击一下标签内文字就改变 class MyComponent2 extends React.Component { constructor(props) { // 调用父类型的构造函数 super(props); // 初始化状态 this.state = { isLikeMe: false } // 将新增方法中的 this 强制绑定为组件对象 (后期可以通过箭头函数来更改方法中 this 的指向) this.handleClick = this.handleClick.bind(this) } // 重写组件类的渲染方法 render() { let { isLikeMe } = this.state; return <h2 onClick={this.handleClick}>{isLikeMe ? 'How would you React if I said I love Vue?' : "tip"}</h2> } // 新添加的方法:内部的 this 默认不是组件对象,而是 undefined handleClick() { // 得到原来的状态 // this.state.isLikeMe // 更新状态 this.setState({ isLikeMe: !this.state.isLikeMe }) } } 这里又和小程序有点像,想要改变 state 状态的话需要 this.setState() 方法只要你的组件有状态 (state),就不可以用工程模式 (只用函数创造组件的模式)

    组件的传值:props

    props 是只读的属性假如我想在不同的组件上渲染不同的值 function Person1(props) { return (<ul> <li>{props.name}</li> <li>{props.age}</li> <li>{props.gender}</li> </ul>) } // 假设这是从后台传过来的值 let p1 = { name: "noobMing", age: 18, gender: "man" } ReactDOM.render(<Person1 name={p1.name} age={p1.age} gender={p1.gender} />, document.querySelector('.person')); 或者我想写成类组件: class Person2 extends React.Component { render() { return (<ul> <li>{this.props.name}</li> <li>{this.props.age}</li> <li>{this.props.gender}</li> </ul>) } } // 注意传值的时候里面要加 this 感觉这个 props 起到了一个传参的作用props 还可以设置默认值: // 例如我有一个 Person 组件 Person.defaultProps = { gender: "man" } 这里我们设置了 gender 的默认属性为 man我们想让某个值是必须的 (例如名字是必填项) 或者对名字进行判断需要引入 prop-types.min.js 这个文件 // 还是那个 Person 组件 Person.propTypes = { // 说明这个属性应该是 string 类型,并且是必须的 name: propTypes.string.isRequired } 渲染部分的 js ReactDOM.render(<Person name={p1.name} age={p1.age} gender={p1.gender} />, document.querySelector('.person')); 里面这部分的写法下面两种是一样的: // 定义一个对象 p1 把他的值传给组件 name={p1.name} age={p1.age} gender={p1.gender} {...p1} 但是我在写这里的时候发生了一个问题:刚开始的时候提示没有引入 propTypes ,当我引入 propTypes 后他会在引入的那行报错,说 require 未定义老师在视频中没有引入也可以使用 propTypes 我即使引入也会报错,但是我发现了问题所在,引入的语句属于 ES6 语法,所以 babel 会将其转化为 ES5 语法,而不知道为什么浏览器没有找到 require 函数的定义,所以才会报错 // 转换前 (ES6) 和转换后 (ES5) 的引入 propTypes 方法 import PropTypes from 'prop-types'; var PropTypes = require('prop-types'); 感觉 props 可以传递各种参数,需要传参的时候只用输出 props 然后在里面要找的参数就可以了

    组件的属性:refs

    ref 主要是标识组件内部的某一个元素感觉 ref 就是一个特殊的属性,它能把组件内的标签绑定到组件对象上,方便以后进行操作 // ref 的实例:绑定 input 里面的值 class Test extends React.Component { constructor(props) { super(props); // 修改 this this.showInput = this.showInput.bind(this); this.handleBlur = this.handleBlur.bind(this); } showInput() { console.log(this.input.value); } handleBlur(event) { // 这两种写法都能找到 input 里面的值 alert(this.input2.value); alert(event.target.value); } render() { return ( <div> // 官方建议的写法 (把当前的 input 元素绑定到组件对象上去了) <input type="text" ref={input => this.input = input} /> <button onClick={this.showInput}>提示</button> <input type="text" onBlur={this.handleBlur} ref={input => this.input2 = input} /> </div> ) } } ReactDOM.render(<Test />, document.querySelector('.base')); 还有一种废弃掉的写法: // 组件的元素 <input type="text" ref="content" /> // 调用的方法 showInput() { // 在函数中找到组件标签 const input = this.refs.content; alert(input.value); }

    组件的嵌套

    注意:vscode 自动生成的 input 标签里面是没有终止符号 / 的,但是在 JSX 里面没有终止符号就会报错

    在使用的时候经常会出现大组件套小组件的情况,这时就需要组件的嵌套

    实例:要实现一个 todo list 页面,需要一个 App 大组件,里面嵌套两个小组件 MyInput 和 MyList 组件分别进行输入和显示

    这里面的一个问题就是 MyInput 组件获取到用户输入之后如何把内容给 MyList 组件

    这里我们把信息储存在他们的上一级组件之中 (App),然后把更新数据的函数当作参数传给 MyInput 组件,这样在子组件里就可以更新上一级组件的里面的信息,然后再把这个数据作为参数传给 MyList 组件,MyList 组件渲染这个列表就有了最简单的 todo 应用的效果

    在子组件中更新父组件里面元素的状态:状态在那个组件,更新状态的函数就应该在哪个组件

    代码:

    // App 组件 class App extends React.Component { constructor(props) { super(props); this.state = { // 用 state 储存输入的内容 todos: [] } this.addtodos = this.addtodos.bind(this); } // 修改 addtodos(todo) { // 获取整个列表 let { todos } = this.state; // 在开头添加数据 todos.unshift(todo); // 渲染回去 this.setState({ todos }); // 不可以这么做:this.state.todos.unshift(todo); } render() { return (<div> <h1>ToDoList</h1> // 把函数当作参数传到子组件上 <MyInput addtodos={this.addtodos} /> <MyList todos={this.state.todos} /> </div>); } } MyInput 组件: class MyInput extends React.Component { constructor(props) { super(props); this.state = { counter: 0, } this.handleClick = this.handleClick.bind(this); } handleClick() { // 设置 button 上的文字 this.setState({ counter: ++this.state.counter }) this.button.innerHTML = "Add #" + this.state.counter; // 调用接收过来的函数 this.props.addtodos(this.input.value); // 清空输入框 this.input.value = null; } render() { return (<div> <input type="text" ref={input => this.input = input} /> <button onClick={this.handleClick} ref={button => this.button = button}>Add #0</button> </div>) } }

    注意:子组件接收参数是在 props 属性里面接收的

    MyList 组件:

    class MyList extends React.Component { render() { console.log(this); // 不得不说,React 渲染列表真的很方便 return (<ul>{this.props.todos.map((todo, index) => { return <li key={index}>{todo}</li> })}</ul>) } } // 渲染 App 组件到页面上 ReactDOM.render(<App />, document.querySelector('.innerInput')); 组件化编写功能的流程 拆分组件实现静态组件(只有静态界面,没有动态数据和交互)实现动态组件 1). 实现初始化数据动态显示 2). 实现交互功能

    在组件中收集表单数据

    阻止默认行为:event.preventDefault()

    原生的 onchange 事件是在失去焦点的时候触发,而 React 中的 onChange 事件是在输入的时候就触发事件

    取出表单中数据有两种方法:使用 ref 在组件对象上绑定好元素;或者使用 state 属性让输入框内容的值 (value) 等于在 state 中定义的变量,然后监听输入框改变的事件,每在输入框中输入都会更新 state 中的数据 (推荐第二种)

    实例:两个输入框分别用 ref 和 state 绑定数据,点击 login 按钮时弹出输入的用户名和密码

    class MyCompent extends React.Component { constructor(props) { super(props); this.state = { pwd: '' } this.handleSubmit = this.handleSubmit.bind(this); this.handleChange = this.handleChange.bind(this); } handleSubmit(event) { // 阻止默认行为 event.preventDefault(); console.log(this.nameInput); alert("用户名" + this.nameInput.value + "密码" + this.state.pwd); } handleChange(event) { // 让输入框和 state 中的数据同步 let pwd = event.target.value; this.setState({ pwd }); } render() { return (<form action="" onSubmit={this.handleSubmit}> <label for="name">name:</label> // 使用 ref 将整个元素绑定到组件对象上 <input type="text" id="name" ref={input => this.nameInput = input} /> <label for="password" >password:</label> // 在 state 中绑定数据,并且绑定监听输入框发生改变事件 handleChange <input type="password" id="password" value={this.state.pwd} onChange={this.handleChange} /> <input type="submit" value="login" /> </form>) } } ReactDOM.render(<MyCompent />, document.querySelector(".form")); 受控组件:表单项输入数据能自动收集成状态 (每输入一个数,后台自动更新输入的数据:state 方法)非受控组件:需要时才手动读取表单输入框中的数据 (点击提交按钮的时候才更新数据:ref 方法)官网不推荐使用 refs 推荐使用 state
    Processed: 0.018, SQL: 9