React 学习笔记
- Hello World
- JSX (JavaScript XML) 语法规则
- JavaScript 语法
- 函数组件、类组件 & 属性 props
- 组合组件
- 生命周期函数 & 状态 state
- 事件处理
- refs
- 受控组件、非受控组件 & 高阶函数、函数的柯里化
- npm
- 参考
Hello World
<!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>Hello, React</title>
</head>
<body>
<div id="root"></div>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<!-- Load Babel -->
<!-- v6 <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Your custom script here -->
<script type="text/babel">
const element = <h1>Hello, World!</h1>;
const container = document.getElementById('root');
// ReactDOM.render(element, container);
ReactDOM.createRoot(container).render(element);
</script>
</body>
</html>
JSX (JavaScript XML) 语法规则
1. 定义虚拟D0M时,不要写引号。
2. 标签中混入JS表达式时要用}。
3. 样式的类名指定不要用class,要用className。
4. 内联样式,要用style={key:value}的形式去写。
5. 只有一个根标签
6. 标签必须闭合
7. 标签首字母
1. 若小写字母开头,则将改标签转为htl中同名元素,若htm1中无该标签对应的同名元素,则报错。
2. 若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。
JavaScript 语法
-
console.log(2, "@");
-
debugger;
-
JSON
JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串
JSON.parse () 方法用来解析 JSON 字符串,构造由字符串描述的 JavaScript 值或对象。JSON.stringify({name:"zhangsan",age:18}) // '{"name":"zhangsan","age":18}' JSON.parse('{"name":"zhangsan","age":18}') // {name: 'zhangsan', age: 18}
-
类中方法默认开启局部严格模式,所以类中自定义方法中的
this
是undefined
,而不是类的实例对象!<script> class Person { constructor(name, age) { this.name = name this.age = age } say() { // 方法在类的原型对象上,供实例使用 console.log(this) } } const p1 = new Person("zhangsan", 13) p1.say() // 通过实例调用,this 是 Person 实例 const say = p1.say say() // 直接调用方法,this 是 undefined console.log("----------------") function fun1() { // 'use strict' console.log(this) // Window 对象- } function fun2() { 'use strict' console.log(this) // undefined } fun1() fun2() </script>
函数组件、类组件 & 属性 props
React 对象三大属性1:props
<body>
<!-- <div id="root"></div> -->
<div id="funId"></div>
<div id="classId"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
// 1. 函数组件,首字母要求大写
function FunctionWelcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 2. 类组件,首字母要求大写,继承 React.Component,React 元素通过 render() 函数返回
class ClassWelcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
// 3. props
// 无论是函数组件,还是类组件,都决不能修改自身的 props。
// React 调用组件,并将 {name: 'XXX'} 作为 props 传入。
// ReactDOM.render(<FunctionWelcome name="老写法"/>, document.getElementById("root"));
ReactDOM.createRoot(document.getElementById("funId")).render(<FunctionWelcome name="韩束"/>);
ReactDOM.createRoot(document.getElementById("classId")).render(<ClassWelcome name="克拉斯"/>);
</script>
</body>
组合组件
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>
</body>
生命周期函数 & 状态 state
React 对象三大属性2:state
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
class Clock extends React.Component {
constructor(props) {
// Class 组件应该始终使用 props 参数来调用父类的构造函数
super(props);
// 初始化状态数据
this.state = { date: new Date() };
}
// 生命周期函数1:组件已被渲染到 DOM 中后调用
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
// 生命周期函数2:组件将卸载时调用
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
// 更新状态数据,必须用 this.setState() 函数。
// 直接修改状态数据无效,如 this.state.date = new Date(); 无效
this.setState({ date: new Date() });
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(<Clock />, document.getElementById('root'));
</script>
</body>
-
组件生命周期函数
componentDidMount
组件已被渲染到 DOM 中后调用componentWillUnmount
组件将卸载时调用
-
state 使用注意事项
-
只能在构造函数或类属性上初始化 state
-
只能使用
this.setState(函数或对象)
更新状态数据,直接更新 state 状态数据无效! -
state 的更新可能是异步的。出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
// Wrong this.setState({ counter: this.state.counter + this.props.increment, }); } // Correct this.setState((state, props) => ({ counter: state.counter + props.increment })); // Correct this.setState(function (state, props) { return { counter: state.counter + props.increment }; });
-
state 的更新会被合并
当你调用setState(对象)
的时候,React 会把你提供的对象合并到当前的 state。 -
除了拥有并设置 state 的组件之外,其他组件都无法访问该 state。不过,组件可以选择把它的 state 作为 props 向下传递到它的子组件中。
-
事件处理
https://zh-hans.reactjs.org/docs/handling-events.html
React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。如
onChange={this.saveUsername}
,其含义为:大括号中同 js语法,将大括号中结果(此处结果为一个函数)赋值给onChange,React 负责调用onChange。 - 在 React 中不能通过返回 false 的方式阻止默认行为,必须显式的使用 preventDefault 。
<body>
<a href="#" onclick="console.log(123);">原生js事件,注意浏览器地址栏URL变化</a><br />
<a href="#" onclick="console.log(123);return false;">原生js通过返回false阻止默认事件</a><br />
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function Fun() {
function handleClick(event) {
event.preventDefault();
console.log(event);
}
return (
<div>
<a href="https://www.baidu.com" onClick={(e) => { handleClick }}>React 通过显示调用阻止默认事件函数阻止事件</a><br />
<a href="https://www.baidu.com" onClick={(e) => { event.preventDefault(); console.log(e.target, e) }}>React 通过显示调用阻止默认事件函数阻止事件, e.target是发生事件的DOM元素</a>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<Fun />)
</script>
</body>
refs
React 对象三大属性3:DOM 节点引用 refs
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
class App extends React.Component {
input4Ref = React.createRef()
input3 = (c) => {
console.log("函数形式", c);
}
render() {
return (
<div>
<input ref="input1" defaultValue="用法1(过时).这是字符串形式ref,效率低" type="text" style={{ width: "50%", color: "#f00" }} name="username" id="uid" /><br />
<input ref={(c) => { this.input2 = c; console.log(c); }} defaultValue="用法2.内联函数形式ref,react会自动调用ref函数,更新过程中会被执行两次,第一次传null,第二次传dom对象" type="text" /><br />
<input ref={this.input3} defaultValue="用法3.回调函数形式的ref,react会自动调用ref函数,更新过程中会被执行两次,第一次传null,第二次传dom对象" type="text" name="username" id="uid" /><br />
<input ref={this.input4Ref} defaultValue="用法4.类绑定的回调,指定回调函数由react创建ref" type="text" name="username" id="uid" /><br />
<input ref={(c) => { this.btn = c }} onClick={(e) => { console.log("不要滥用ref,譬如此按钮的ref可以省略", e.target === this.btn); console.log(1, this.refs.input1); console.log(2, this.input2); console.log(3, this.input3); console.log(4, this.input4Ref.current); this.input4Ref.current.value = "React.createRef"; }} type="button" value="click" />
</div>
);
}
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />)
</script>
</body>
受控组件、非受控组件 & 高阶函数、函数的柯里化
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
class FormApp extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
const { username, password } = this;
// alert("用户名:" + username.value + ", 密码:" + password.value)
alert(`用户名:${username.value},密码:${password.value}`);
}
state = {
username: "",
password: ""
}
saveUsername = (e) => {
this.setState({ username: e.target.value });
}
savePassword = (e) => {
this.setState({ password: e.target.value });
}
handleSubmit2 = (event) => {
event.preventDefault();
alert(`用户名:${this.state.username},密码:${this.state.password}`);
}
// 高阶函数:参数或返回值也为函数的函数。
// 函数的柯里化:通过函数调用继续返回函数的方式,多次接收参数最后统一处理的函数编码形式。
// 如定义:
// f = (a) => {
// return (b) => {
// return (c) => {
// return a + b + c;
// }
// }
// }
// console.log(f(1)(2)(3)) // 6
saveData = (dataType) => {
return (event) => {
this.setState({ [dataType]: event.target.value });
}
}
render() {
return (
<div>
<h1>非受控组件,大量使用ref,性能相对低(不太推荐)</h1>
<form method="post" action="http://www.baidu.com" onSubmit={this.handleSubmit}>
用户名:<input ref={c => this.username = c} type="text" name="username" /><br />
密码:<input ref={c => this.password = c} type="password" name="password" /><br />
{/* <input type="submit" value="登陆"/>*/}
<button>登陆</button>
</form><br />
<h1>受控组件(推荐)</h1>
<form method="post" action="http://www.baidu.com" onSubmit={this.handleSubmit2}>
用户名:<input onChange={this.saveUsername} type="text" name="username" /><br />
密码:<input onChange={this.savePassword} type="password" name="password" /><br />
<button>登陆</button>
</form>
<h1>高阶函数(更推荐)</h1>
<form method="post" action="http://www.baidu.com" onSubmit={this.handleSubmit2}>
用户名:<input onChange={this.saveData("username")} type="text" name="username" /><br />
密码:<input onChange={this.saveData("password")} type="password" name="password" /><br />
<button>登陆</button>
</form>
</div>
);
}
}
ReactDOM.createRoot(document.getElementById("root")).render(<FormApp />);
</script>
</body>
npm
npm(“Node 包管理器”)是 JavaScript 运行时 Node.js 的默认程序包管理器。
npm 由两个主要部分组成:
用于发布和下载程序包的 CLI(命令行界面)工具
托管 JavaScript 程序包的 在线存储库
参考
- React 官方中文教程
- ES6 入门教程
- Babel 官网
- 尚硅谷 React 视频教程
- 什么是 npm —— 写给初学者的编程教程