前言:我的前端学习之路是从Vue开始的,为了更快的形成生产力,我直接选择了Vue去学习,目前也算基本掌握了。但是我的基本功其实并没有那么优秀。所以我选择抓住机会参加了字节跳动的青训营,在青训营中重新学习前端知识,我称之重识之路。青训营授课中将会提及React,所以我也趁此机会去学习下React,以下就是我学习过程中想要记录的一些知识点又或者是感悟。
所有内容全基于本人观点,参考意义极其有限
采用对比学习,提及Vue内容均无踩一捧一的意思
「响应式系统与 React」课程笔记
React的设计思路
UI编程的痛点:
- 状态更新,UI不会自动更新,需要手动调动DOM更新。
- 欠缺代码的封装和隔离,代码层面没有组件化。
- 需要手动维护依赖关系,如果依赖链路过长,会出现“回调地域”。
常见的系统:
转换式系统和响应式系统
转换式系统
- 给定输入求输出(值->值)
响应式系统
- 监听事件,消息驱动(事件->事件)
事件->执行既定的回调->状态变更->UI更新
响应式编程特点
- 状态更新,UI自动更新
- 前端代码组件化,可复用封装
- 状态之间的依赖关系,只需声明即可。
组件化的准则
- 组件是组件的组合/原子组件
- 组件内拥有状态,外部不可见
- 父组件可将状态传入组件内部
组件设计:
- 组件声明了状态和UI映射
- 组件有Props/State两种状态
- 组件可以组合
React的写法
Hooks
useState 是允许你在 React 函数组件中添加 state 的 Hook
useState() 方法里面唯一的参数就是初始 state
useState 返回值为:当前 state 以及更新 state 的函数:[state名,setState方法]
useEffect通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。
Hook还是建议看官方文档:react.docschina.org/docs/hooks-…
如何解决状态不合理上升的问题?(状态管理库)
避免所有状态堆积。
核心思想:抽离状态到UI外部统一管理。
推荐:
- redux
- xstate
- mobx
- recoil
状态机:当前状态,收到外部事件,迁移到下一个状态。
应用级框架科普
- next.js
- modern.js
- Blitz
React学习笔记
React是践行组件化的一个库,它提供的是函数式的编程。
React的官方文档我认为是最好的学习工具,它非常贴心,它分别为喜欢动手和喜欢从概念学起的人提供了两种方案。
我的顺序是从 动手->概念
初识JSX
React的组件是使用JSX是一个 JavaScript 的语法扩展,它的形式如下:
const element = <h1>Hello, world!</h1>;
既不是字符串也不是html的。
元素渲染
React中想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render()
我的理解:
React的元素虽然都是组件,但是不用重复的渲染他们,而只用渲染他们的顶层组件。
同时React由于diff算法的使用,使得它可以精准定位变化处,从而单独渲染变化处,而不用全部重新渲染,因此它的性能也算非常优秀的。
组件
React组件声明共有两种形式:函数组件与 class 组件
函数组件:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class组件:
class Welcome extends React.Component {
constructor(props){
super(props);
this.state={
key:value,
};
}
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
class组件主要是基于ES6的更新产生的。它标配一个render()它返回JSX,如果你要使用state,那你必须使用constructor,并且传入参数和super()、this.state定义是必须的。
函数组件的话,在实践教程中提到,如果你不需要state,那你可以直接使用函数组件,虽然React hook也使得函数组件可以使用state,但是那都是后续学习的内容了。
如何渲染和组合组件
其实只需要使用标签的形式就可以实现,如下:
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')
);
这里App组件被渲染到root下,App组件中又组合了Welcome组件。
组件的渲染方式就是使用标签的形式(注意规范,组件名大写)。
标签中传入的属性将会存放在props中,通过this.props.属性名取值。
props和state
props和state是组件中最重要的两个概念,它是数据的载体。
必须注意的: props不可赋值。
props是只读的,它是只向下的。也就是说它是父组件传值的工具,子组件只能接受而不能改变。
state是组件自身属性,它可以修改、读取。
state需要注意的点:
- 不要直接修改 State 例如,此代码不会重新渲染组件:
// Wrong
this.state.comment = 'Hello';
而是应该使用 setState():
// Correct
this.setState({comment: 'Hello'});
构造函数是唯一可以给 this.state 赋值的地方:
- State 的更新可能是异步的
要解决这个问题,可以让
setState()接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数
例如,此代码可能会无法更新计数器:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
修改后是这样:
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
组件中的值如何显示
在vue中如果我们想要展示一个数据那么可以使用{{value}}直接显示。
在React中也类似如此使用{表达式}的形式进行读取值,或者调用函数。
这里需要注意的是:{}中仅能使用单独的表达式而不是大堆的代码;
比如:
<h1>{add(x,y)}</h1>
//错误的例子
<h1>{
function add(x,y){
return x+y;
}
}</h1>
React的事件处理
规范:
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
例如,传统的 HTML:
<button onclick="activateLasers()">
Activate Lasers
</button>
在 React 中略微不同:
<button onClick={activateLasers}> Activate Lasers
</button>
使用 React 时,你一般不需要使用 addEventListener 为已创建的 DOM 元素添加监听器。事实上,你只需要在该元素初始渲染的时候添加监听器即可。
如果使用ES6的方式创建组件,并且在state声明了方法,记得一定要加bind,否则this指向会出问题。
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 为了在回调中使用 `this`,这个绑定是必不可少的 this.handleClick = this.handleClick.bind(this); }
handleClick() { this.setState(state => ({ isToggleOn: !state.isToggleOn })); }
render() {
return (
<button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
React的生命周期
如图所示(来源):
React的生命周期相比Vue的就简单多了,在文档中举例说明了componentDidMount()和componentWillUnmount()。
componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行。
componentWillUnmount()方法是在组件卸载前运行。
条件渲染
在Vue中条件渲染使用的是v-if,但是在React中并没有这样的封装,所以在这里只能通过if或者三目判断之类的方法返回所需要渲染的组件。
例子如下:
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) { return <UserGreeting />; } return <GuestGreeting />;}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />, document.getElementById('root'));
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn? <LogoutButton onClick={this.handleLogoutClick} />
: <LoginButton onClick={this.handleLoginClick} /> }
</div> );
}
如果需要阻止渲染,组件return null即可。
列表 & Key
在Vue中我们可以通过v-for实现,但是在React中是用原生方法,比如map()
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li>{number}</li>);
并且和vue一样必须都拥有一个key。
表单受控组件
在vue中可以使用v-model进行双向绑定,React中必须通过绑定方法实现,例如值绑定state中的值,并且加入onChange方法绑定一个handle方法。每当用户输入信息,触发onChange,触发handle,handle进行setState操作。
例如,如果我们想让前一个示例在提交时打印出名称,我们可以将表单写为受控组件:
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('提交的名字: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input type="text" value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="提交" />
</form>
);
}
}
更多表单内容参考文档。
状态提升
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。让我们看看它是如何运作的。
这一部分如果不太理解,建议重新看一遍边做边学的[入门教程]。(react.docschina.org/tutorial/tu…)
组合 vs 继承
包含关系
如果你在写组件是不太确定是否这个组件后续有没有子组件,你可以使用{props.children}来占位。
在后续组合组件时,如果确定了,将子组件直接嵌套在标签中,就会自动替换{props.children}。
例如:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children} </div>
);
}
特例关系
如果不是简单的父子关系,而是可能临时使用如title一类的,可以使用{props.title}占位
在确定title内容后,在组件标签中传值即可实现。
React哲学
这一部分其实就是React引导思考如何开发一个优秀的SPA的分析。
简单地说就是如何写好一个React应用。
具体内容请查看官方文档,这里只写步骤。
- 将设计好的 UI 划分为组件层级
- 用 React 创建一个静态版本
- 确定 UI state 的最小(且完整)表示
- 确定 state 放置的位置
- 添加反向数据流
基础部分到此结束
React脚手架的使用
首先下载create-react-app
npm install -g create-react-app
创建一个应用
npm init react-app my-app
启动应用
npm start
react-router-dom的学习
这一部分踩坑有点多,主要是V6的更新让好多教程内容失效了。
router的声明不同vue是单独文件,React的router是在组件jsx声明的。
以下纯属个人简单理解:
它结构大概如下:
<Router>
<Link>...
<Routes>
<Route>...
</Routes>
</Router>
<Router>可以替换成# <BrowserRouter>或者# <HashRouter>,代表不同模式。
<Link>提供声明式、可访问的导航
<Route>声明路由和渲染组件的位置和渲染什么组件。必须放在<Routes>里
简单小demo如下:
import React from 'react'
import './App.css';
import {BrowserRouter, Route,Link, Routes} from 'react-router-dom';
import Home from "./Componnent/Home/Home.jsx";
import Hi from "./Componnent/Hi/Hi.jsx";
function App() {
return (
<BrowserRouter>
<div className="App">
<ul>
<li><Link to="/hi">你好</Link></li>
<li><Link to="/home">主页</Link></li>
</ul>
<div>
<Routes>
<Route path="/hi" element={<Hi />}/>
</Routes>
</div>
</div>
</BrowserRouter>
);
}
export default App;
这一部分还需要继续学习。。。
准备阅读文章:juejin.cn/post/702541…
To Be Continue......