React课堂笔记1
一、概要
React是用于构建用户界面的MVVM框架。
使用JSX语法
JSX (JavaScript XML) 是 JavaScript 语法的扩展。React 开发大部分使用 JSX 语法(在JSX中可以将HTML于JS混写)。
灵活
react所控制的dom就是id为root的dom,页面上的其他dom元素你页可以使用jq等其他框架 。可以和其他库并存。
使用虚拟DOM、高效
虚拟DOM其实质是一个JavaScript对象,当数据和状态发生了变化,都会被自动高效的同步到虚拟DOM中,最后再将仅变化的部分同步到DOM中(不需要整个DOM树重新渲染)。
单向数据流
react是单向数据流,父组件传递给子组件的数据,子组件能够使用,但是不能直接通过this.props修改。 这样让数据清晰代码容易维护。
1.原生JS操作DOM繁琐,效率低
2.使用JS直接操作DOM,浏览器会进行大量的重绘重排
3.原生JS没有组件化编码方案,代码复用低
三、React相关技术
- React可以开发Web应用—ReactJs
- React可以开发移动端—React-native
- React Native 是一个使用JavaScript 和 React 来编写跨终端移动应用(Android 或 IOS)的一种解决方案
-
- React 360是一个创建3D和VR用户交互的框架.构建在React的基础之上,React是一个简化复杂UI创建的库,React 360可以让你用相似的工具和概念在网页上创建沉浸式的360度的内容。其特点:
-
React 360 是一个用于构建VR全景360体验的网页应用框架,基于React
-
React 360 提供了一些控件,用于快速创建360度沉浸式的内容
-
跨平台,支持电脑、移动设备、VR设备
-
支持多种格式的全景视频
-
- React 360是一个创建3D和VR用户交互的框架.构建在React的基础之上,React是一个简化复杂UI创建的库,React 360可以让你用相似的工具和概念在网页上创建沉浸式的360度的内容。其特点:
四、创建第一个程序
4.1、Web端
1、准备一个空文件夹,打开终端输入命令 npm init -y 下载 package.json文件。
在目录下创建一个index.html文件
2、实例中我们引入了三个库: react.development.min.js 、react-dom.development.min.js 和 babel.min.js
方法有两种,一种本地下载,在终端输入指令npm i react react-dom。第二种是直接搜索网上
3、编写代码
写一个<div id="app"></div>
<script> // 参数一,h2表示标签的名称 // 参数二,{}表示节点中的属性如,{title:"Hello"} // 参数三,表示子节点,可以是文本节点 // 1、创建虚拟DOM节点 let vNode = React.createElement("h2", { title: "Hello" }, "Hello React Web!"); // 2、找到根节点 let app = document.querySelector("#app"); // 3、创建根节点 let root = ReactDOM.createRoot(app); // 4、将虚拟DOM挂载到根节点上 root.render(vNode); </script>
运行结果
4.2、JSX
代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>React案例2</title> <style> .purple { color: blueviolet; } </style> </head> <body> <div id="app"></div> <!-- 三个库,react核心库,提供与dom相关的功能,bable可以将es6代码转换es5代码 --> <script src="https://cdn.staticfile.org/react/18.2.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/18.2.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/7.20.6/babel.min.js"></script> <!-- 需要bable解析 --> <script type="text/babel"> // 1、创建虚拟DOM节点 vnode, 对比:React.createElement("h2", { title: "Hello" }, "Hello React Web!"); let vNode = ( <div class="purple"> <h2 title="Hello" >Hello React JSX!</h2> </div> ) // 2、创建根节点 let root = ReactDOM.createRoot(document.getElementById("app")); // 3、将虚拟DOM挂载到根节点上 root.render(vNode); </script> </body> </html>
4.3、脚手架
1.使用 create-react-app 脚手架创建项目
npx create-react-app 项目名 或者 yarn create react-app 项目名(npx 是一个临时使用第三方模块的命令,会临时下载这个包,使用完毕就删除了)
npm和npx的区别
区别1.一个永久存在(npm),一个临时安装(npx),用完后删除
区别2.npx 会帮你执行依赖包里的二进制文件。也就是说 npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去环境变量里面的 PATH 里找。如果依然找不到,就会帮你安装!
区别3.npx可以执行文件,但是npm不可以
虽然在本地搭建环境要费一些时间,但是你可以选择自己喜欢的编辑器来完成开发。以下是具体步骤:
- 确保你安装了较新版本的 Node.js。
- 按照 Create React App 安装指南创建一个新的项目
npx create-react-app my-app
3.删除掉新项目中 src/
文件夹下的所有文件。
4.4、vite+react项目
使用vite创建项目比较快,文件少,根据提示第一个输入项目名称,第二个选择是React,第三个选择TypeScript。
4.5、官网四个demo案例
这四个案例使用组件完成。
main.tsx文件
import React from 'react' import ReactDOM from 'react-dom/client' import HelloMessage from './HelloMessage' import MarkdownEditor from './MarkdownEditor' import Timer from './Timer' import TodoApp from './TodoApp' ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( <React.StrictMode> <HelloMessage name="Taylor" /> <Timer/> <TodoApp></TodoApp> <MarkdownEditor></MarkdownEditor> </React.StrictMode> )
组件HelloMessage.tsx文件
import React from 'react' export default class HelloMessage extends React.Component<any> { render() { return <div>Hello {this.props.name}</div>; } }
组件 Timer.tsx
import React from 'react' export default class Timer extends React.Component<any,any> { interval: number | undefined; constructor(props: any) { super(props); this.state = { seconds: 0 }; } tick() { this.setState((state: { seconds: number; }) => ({ seconds: state.seconds + 1 })); } componentDidMount() { this.interval = setInterval(() => this.tick(), 1000); } componentWillUnmount() { clearInterval(this.interval); } render() { return ( <div> Seconds: {this.state.seconds} </div> ); } }
组件TodoApp.tsx文件
import React from 'react' export default class TodoApp extends React.Component<any,any> { constructor(props: any) { super(props); this.state = { items: [], text: '' }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } render() { return ( <div> <h3>TODO</h3> <TodoList items={this.state.items} /> <form onSubmit={this.handleSubmit}> <label htmlFor="new-todo"> What needs to be done? </label> <input id="new-todo" onChange={this.handleChange} value={this.state.text} /> <button> Add #{this.state.items.length + 1} </button> </form> </div> ); } handleChange(e: { target: { value: any; }; }) { this.setState({ text: e.target.value }); } handleSubmit(e: { preventDefault: () => void; }) { e.preventDefault(); if (this.state.text.length === 0) { return; } const newItem = { text: this.state.text, id: Date.now() }; this.setState((state: { items: any[]; }) => ({ items: state.items.concat(newItem), text: '' })); } } class TodoList extends React.Component { render() { return ( <ul> {this.props.items.map((item: { id: React.Key | null | undefined; text: string | number | boolean | React.ReactElement<any, string | React.JSXElementConstructor<any>> | React.ReactFragment | React.ReactPortal | null | undefined; }) => ( <li key={item.id}>{item.text}</li> ))} </ul> ); } }
组件MarkdownEditor.tsx文件
import React from 'react' import { Remarkable } from 'remarkable'; export default class MarkdownEditor extends React.Component<any,any> { md: any; constructor(props: any) { super(props); this.md = new Remarkable(); this.handleChange = this.handleChange.bind(this); this.state = { value: 'Hello, **world**!' }; } handleChange(e: { target: { value: any; }; }) { this.setState({ value: e.target.value }); } getRawMarkup() { return { __html: this.md.render(this.state.value) }; } render() { return ( <div className="MarkdownEditor"> <h3>Input</h3> <label htmlFor="markdown-content"> Enter some markdown </label> <textarea id="markdown-content" onChange={this.handleChange} defaultValue={this.state.value} /> <h3>Output</h3> <div className="content" dangerouslySetInnerHTML={this.getRawMarkup()} /> </div> ); } }
需要用到插件,添加依赖:npm install remarkable --save
五、安装插件
为以后的react项目做准备
5.1、安装React开发调试插件
- 进入到【谷歌扩展程序】界面。在谷歌浏览器直接输入: chrome://extensions/ 即可进去扩展程序界面。
- 把 .crx 结尾的文件拖入浏览器即可。
- 运行 react 项目,打开控制台,就可以看到了。
5.2、安装VSCode插件
React/Redux/React-Native snippets 代码模板/代码片段
每个插件都会在页面显示怎么使用,这个也不例外
例子
rcc import React, { Component } from 'react' export default class FileName extends Component { render() { return <div>$2</div> } } rce import React, { Component } from 'react' export class FileName extends Component { render() { return <div>$2</div> } } export default $1 rcep import React, { Component } from 'react' import PropTypes from 'prop-types' export class FileName extends Component { static propTypes = {} render() { return <div>$2</div> } } export default $1 rpc import React, { PureComponent } from 'react' export default class FileName extends PureComponent { render() { return <div>$2</div> } } rpcp import React, { PureComponent } from 'react' import PropTypes from 'prop-types' export default class FileName extends PureComponent { static propTypes = {} render() { return <div>$2</div> } } rpce import React, { PureComponent } from 'react' import PropTypes from 'prop-types' export class FileName extends PureComponent { static propTypes = {} render() { return <div>$2</div> } } export default FileName rccp import React, { Component } from 'react' import PropTypes from 'prop-types' export default class FileName extends Component { static propTypes = { $2: $3, } render() { return <div>$4</div> } } rfcp import React from 'react' import PropTypes from 'prop-types' function $1(props) { return <div>$0</div> } $1.propTypes = {} export default $1 rfc import React from 'react' export default function $1() { return <div>$0</div> } rfce import React from 'react' function $1() { return <div>$0</div> } export default $1 rafcp import React from 'react' import PropTypes from 'prop-types' const $1 = (props) => { return <div>$0</div> } $1.propTypes = {} export default $1 rafc import React from 'react' export const $1 = () => { return <div>$0</div> } rafce import React from 'react' const $1 = () => { return <div>$0</div> } export default $1 rmc import React, { memo } from 'react' export default memo(function $1() { return <div>$0</div> }) rmcp import React, { memo } from 'react' import PropTypes from 'prop-types' const $1 = memo(function $1(props) { return <div>$0</div> }) $1.propTypes = {} export default $1 rcredux import React, { Component } from 'react' import { connect } from 'react-redux' export class FileName extends Component { render() { return <div>$4</div> } } const mapStateToProps = (state) => ({}) const mapDispatchToProps = {} export default connect(mapStateToProps, mapDispatchToProps)(FileName) rcreduxp import React, { Component } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' export class FileName extends Component { static propTypes = { $2: $3, } render() { return <div>$4</div> } } const mapStateToProps = (state) => ({}) const mapDispatchToProps = {} export default connect(mapStateToProps, mapDispatchToProps)(FileName) rfcredux import React, { Component } from 'react' import { connect } from 'react-redux' export const FileName = () => { return <div>$4</div> } const mapStateToProps = (state) => ({}) const mapDispatchToProps = {} export default connect(mapStateToProps, mapDispatchToProps)(FileName) rfreduxp import React, { Component } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' export const FileName = () => { return <div>$4</div> } FileName.propTypes = { $2: $3, } const mapStateToProps = (state) => ({}) const mapDispatchToProps = {} export default connect(mapStateToProps, mapDispatchToProps)(FileName) reduxmap const mapStateToProps = (state) => ({}) const mapDispatchToProps = {} React Native Components rnc import React, { Component } from 'react' import { Text, View } from 'react-native' export default class FileName extends Component { render() { return ( <View> <Text> $2 </Text> </View> ) } } rnf import React from 'react' import { View, Text } from 'react-native' export default function $1() { return ( <View> <Text> $2 </Text> </View> ) } rnfs import React from 'react' import { StyleSheet, View, Text } from 'react-native' export default function $1() { return ( <View> <Text> $2 </Text> </View> ) } const styles = StyleSheet.create({}) rnfe import React from 'react' import { View, Text } from 'react-native' const $1 = () => { return ( <View> <Text> $2 </Text> </View> ) } export default $1 rnfes import React from 'react' import { StyleSheet, View, Text } from 'react-native' const $1 = () => { return ( <View> <Text> $2 </Text> </View> ) } export default $1 const styles = StyleSheet.create({}) rncs import React, { Component } from 'react' import { Text, StyleSheet, View } from 'react-native' export default class FileName extends Component { render() { return ( <View> <Text> $2 </Text> </View> ) } } const styles = StyleSheet.create({}) rnce import React, { Component } from 'react' import { Text, View } from 'react-native' export class FileName extends Component { render() { return ( <View> <Text> $2 </Text> </View> ) } } export default $1 Others cmmb /** |-------------------------------------------------- | $1 |-------------------------------------------------- */ desc describe('$1', () => { $2 }) test test('should $1', () => { $2 }) tit it('should $1', () => { $2 }) stest import React from 'react' import renderer from 'react-test-renderer' import { $1 } from '../$1' describe('<$1 />', () => { const defaultProps = {} const wrapper = renderer.create(<$1 {...defaultProps} />) test('render', () => { expect(wrapper).toMatchSnapshot() }) }) srtest import React from 'react' import renderer from 'react-test-renderer' import { Provider } from 'react-redux' import store from 'src/store' import { $1 } from '../$1' describe('<$1 />', () => { const defaultProps = {} const wrapper = renderer.create( <Provider store={store}> <$1 {...defaultProps} />) </Provider>, ) test('render', () => { expect(wrapper).toMatchSnapshot() }) }) sntest import 'react-native' import React from 'react' import renderer from 'react-test-renderer' import $1 from '../$1' describe('<$1 />', () => { const defaultProps = {} const wrapper = renderer.create(<$1 {...defaultProps} />) test('render', () => { expect(wrapper).toMatchSnapshot() }) }) snrtest import 'react-native' import React from 'react' import renderer from 'react-test-renderer' import { Provider } from 'react-redux' import store from 'src/store/configureStore' import $1 from '../$1' describe('<$1 />', () => { const defaultProps = {} const wrapper = renderer.create( <Provider store={store}> <$1 {...defaultProps} /> </Provider>, ) test('render', () => { expect(wrapper).toMatchSnapshot() }) }) hocredux import React from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' export const mapStateToProps = (state) => ({}) export const mapDispatchToProps = {} export const $1 = (WrappedComponent) => { const hocComponent = ({ ...props }) => <WrappedComponent {...props} /> hocComponent.propTypes = {} return hocComponent } export default (WrapperComponent) => connect(mapStateToProps, mapDispatchToProps)($1(WrapperComponent)) hoc import React from 'react' import PropTypes from 'prop-types' export default (WrappedComponent) => { const hocComponent = ({ ...props }) => <WrappedComponent {...props} /> hocComponent.propTypes = {} return hocComponent }
5.3、Simple React Snippets 更加简洁的代码片段
Snippet | Renders |
---|---|
imr |
Import React |
imrc |
Import React / Component |
imrd |
Import ReactDOM |
imrs |
Import React / useState |
imrse |
Import React / useState useEffect |
impt |
Import PropTypes |
impc |
Import React / PureComponent |
cc |
Class Component |
ccc |
Class Component With Constructor |
cpc |
Class Pure Component |
ffc |
Function Component |
sfc |
Stateless Function Component (Arrow function) |
cdm |
componentDidMount |
uef |
useEffect Hook |
cwm |
componentWillMount |
cwrp |
componentWillReceiveProps |
gds |
getDerivedStateFromProps |
scu |
shouldComponentUpdate |
cwu |
componentWillUpdate |
cdu |
componentDidUpdate |
cwun |
componentWillUnmount |
cdc |
componentDidCatch |
gsbu |
getSnapshotBeforeUpdate |
ss |
setState |
ssf |
Functional setState |
usf |
Declare a new state variable using State Hook |
ren |
render |
rprop |
Render Prop |
hoc |
Higher Order Component |
cp |
Context Provider |
cpf |
Class Property Function |
好了,第一节结束!